React: 如何在第一次渲染时跳过 useEffect
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"}
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 ) }
如果有帮助,请告诉我。
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之后,我从未遇到过这种情况。
问题的原因是在使用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 { // 在第一次渲染后执行一些操作 } });
这样,就可以解决问题并避免警告的出现。