React: 如何在第一次渲染时跳过 useEffect

15 浏览
0 Comments

React: 如何在第一次渲染时跳过 useEffect

我正在尝试在受控表单组件中使用useEffect钩子,以便在用户更改表单内容时通知父组件并返回表单内容的DTO。这是我的当前尝试:

const useFormInput = initialValue => {
  const [value, setValue] = useState(initialValue)
  const onChange = ({target}) => {
    console.log("onChange")
    setValue(target.value)
  }
  return { value, setValue, binding: { value, onChange }}
}
useFormInput.propTypes = {
  initialValue: PropTypes.any
}
const DummyForm = ({dummy, onChange}) => {
  const {value: foo, binding: fooBinding} = useFormInput(dummy.value)
  const {value: bar, binding: barBinding} = useFormInput(dummy.value)
  // 这只应在初始渲染后用户编辑输入时运行
  useEffect(() => {
    console.log("onChange callback")
    onChange({foo, bar})
  }, [foo, bar])
  return (
      
      {foo}
      
      {bar}
  )
}
function App() {
  return (
      
console.log(dummy)} />
); }

然而,现在该效果在第一次渲染时运行,而在挂载时设置初始值。我该如何避免这种情况?

这是加载页面和随后编辑两个字段的当前日志。我还想知道为什么我会收到缺少依赖项的警告。

onChange callback
App.js:136 {foo: "Initial", bar: "Initial"}
backend.js:1 ./src/App.js
  Line 118:  React Hook useEffect has a missing dependency: 'onChange'. Either include it or remove the dependency array. If 'onChange' changes too often, find the parent component that defines it and wrap that definition in useCallback  react-hooks/exhaustive-deps
r @ backend.js:1
printWarnings @ webpackHotDevClient.js:120
handleWarnings @ webpackHotDevClient.js:125
push../node_modules/react-dev-utils/webpackHotDevClient.js.connection.onmessage @ webpackHotDevClient.js:190
push../node_modules/sockjs-client/lib/event/eventtarget.js.EventTarget.dispatchEvent @ eventtarget.js:56
(anonymous) @ main.js:282
push../node_modules/sockjs-client/lib/main.js.SockJS._transportMessage @ main.js:280
push../node_modules/sockjs-client/lib/event/emitter.js.EventEmitter.emit @ emitter.js:53
WebSocketTransport.ws.onmessage @ websocket.js:36
App.js:99 onChange
App.js:116 onChange callback
App.js:136 {foo: "Initial1", bar: "Initial"}
App.js:99 onChange
App.js:116 onChange callback
App.js:136 {foo: "Initial1", bar: "Initial2"}

0
0 Comments

React中的useEffect()是用于处理副作用的钩子函数,它可以在组件渲染完成后执行一些额外的操作。但有时候我们需要在第一次渲染时跳过useEffect()的执行,只在之后的渲染时执行。下面是一个解决这个问题的方法:

首先,我们可以自定义一个钩子函数useComponentDidMount()来实现类似于componentDidUpdate()但不包括componentDidMount()的功能。代码如下:

export const useComponentDidMount = () => {
  const ref = useRef();
  useEffect(() => {
    ref.current = true;
  }, []);
  return ref.current;
};

在组件中,我们可以使用这个自定义的钩子函数。代码如下:

const isComponentMounted = useComponentDidMount();
useEffect(() => {
 if(isComponentMounted) {
  // 在之后的渲染时执行
 }
}, [someValue])

在你的具体情况中,代码如下:

const DummyForm = ({dummy, onChange}) => {
  const isComponentMounted = useComponentDidMount();
  const {value: foo, binding: fooBinding} = useFormInput(dummy.value)
  const {value: bar, binding: barBinding} = useFormInput(dummy.value)
  // 只在初始渲染后用户编辑输入时执行
  useEffect(() => {
    if(isComponentMounted) {
      console.log("onChange回调")
      onChange({foo, bar})
    }
  }, [foo, bar])
  return (
    // code
  )
}

如果有帮助,请告诉我。

0
0 Comments

React中的useEffect钩子用于处理副作用操作,它会在组件渲染完成后执行。然而,在某些情况下,我们希望在首次渲染时跳过useEffect的执行。面对这个问题,有一种解决方法是创建一个自定义的hook,名为useSkipFirstRender。

下面是一个简单的使用useSkipFirstRender的示例代码:

const useSkipFirstRender = (fn, args) => {
  const isMounted = useRef(false);
  useEffect(() => {
    if (isMounted.current) {
      console.log('running');
      return fn();
    }
  }, args);
  useEffect(() => {
    isMounted.current = true;
  }, []);
};

在这段代码中,第一个useEffect是主要的效果,就像在组件中使用它一样。它会执行,发现isMounted不是true,然后跳过任何操作。

然后,在底部的第二个useEffect运行后,它会将isMounted更改为true。因此,当组件被强制重新渲染时,它将允许第一个useEffect正常渲染。

这个自定义hook非常简洁且可重用。你可以根据自己的需要更改名称。

作者对于使用ref来处理这样一个简单的任务感到抱歉。希望React团队能够调整hook API,解决这个普遍存在的问题。虽然React文档中已经明确表示这是一个非常罕见的情况,因此尚未实现。

这确实是一个有趣的案例,在我理解hooks之后,我从未遇到过这种情况。

0
0 Comments

问题的原因是在使用React的useEffect钩子时,出现了一个警告,警告信息是"React Hook useEffect has a missing dependency: 'onChange'"。这个警告是因为在useEffect钩子的依赖数组中缺少了一个名为'onChange'的依赖。

解决方法是将'onChange'添加到useEffect钩子的依赖数组中,以便在'onChange'发生变化时重新运行useEffect钩子。具体的解决方法如下所示:

useEffect(() => {
  // 在这里执行一些操作
}, [onChange]);

此外,还可以参考一个回答中的方法来忽略初始渲染。该方法使用useRef钩子来跟踪第一次渲染。具体的代码如下所示:

const firstUpdate = useRef(true);
useLayoutEffect(() => {
  if (firstUpdate.current) {
    firstUpdate.current = false;
  } else {
    // 在第一次渲染后执行一些操作
  }
});

这样,就可以解决问题并避免警告的出现。

0