useCallback依赖数组是否需加入父组件传递的onClick方法?
组件代码示例:
JavaScript代码:
const {useState, useCallback} = React; const ComponentB = (props) => { const [text, setText] = useState('') const { onClick } = props const handleChange = useCallback((event) => { setText(event.target.value) }, [text]) const handleClick = useCallback(() => { onClick(text) }, [onClick, text]) // 是否需要把'onClick'加入依赖? return ( <div> <input type="text" onChange={ handleChange } /> <button type="button" onClick={ handleClick }>Save</button> </div> ) } const ComponentA = () => { const [stateA, setStateA] = useState('') const handleSetStateA = useCallback((state) => { setStateA(state) }, [stateA]) return ( <div> <ComponentB onClick={ handleSetStateA } /> { stateA && `${ stateA } saved!` } </div> ) } ReactDOM.createRoot( document.getElementById("root") ).render( <ComponentA /> );
HTML代码:
<div id="root"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react-dom.development.js"></script>
根据React官方文档:“回调中引用的每个值都应出现在依赖数组中”,现咨询:是否需要将props传递的onClick方法加入useCallback的依赖数组?若需要,原因是什么?
必须把props传递的onClick加入useCallback的依赖数组,原因如下:
遵循React官方规则与lint校验要求
React官方明确规定,hooks回调中用到的所有外部值都要放进依赖数组,这是hooks核心设计原则之一。如果不添加,eslint-plugin-react-hooks会直接抛出警告,这也是React团队为避免潜在问题设置的校验机制。避免过时闭包导致的逻辑错误
父组件传递的onClick函数并非一成不变——比如父组件可能因为自身状态变化,通过useCallback重新生成新的onClick函数(就像例子里的handleSetStateA依赖了stateA,每次stateA变化都会生成新函数)。如果子组件的handleClick不把onClick加入依赖,就会一直捕获旧版本的onClick函数,点击按钮时调用的是过时方法,导致行为不符合预期。保证组件行为的一致性
就算父组件没给onClick加useCallback,每次父组件渲染都会生成新的onClick函数。如果子组件的handleClick不依赖onClick,就不会同步更新,此时子组件的点击事件绑定的始终是第一次渲染时的旧函数,完全达不到父组件传递新函数的预期效果。
另外补充个小细节:例子里父组件的handleSetStateA其实不需要把stateA放进依赖数组,因为setStateA是useState返回的稳定函数,不会随组件渲染变化,所以handleSetStateA的依赖数组可以改成[],能减少不必要的函数重新生成。
内容的提问来源于stack exchange,提问作者cccn

