未在React useEffect依赖数组中填全所有依赖的风险是什么?
React useEffect依赖数组的ESLint警告与潜在风险
为什么ESLint会警告缺失依赖?
ESLint的react-hooks/exhaustive-deps规则核心目的,是帮你避免effect使用过期闭包值的问题。React的effect回调会捕获当前渲染周期的所有变量快照,如果依赖数组没列全,当那些未被声明的变量发生变化时,effect不会重新执行,会一直沿用旧渲染周期里的变量值——这几乎都是不符合预期的隐性bug。
拿你给出的代码举例:
useEffect(() => { api.send(someUrl, somePayload); }, [changeMe]);
假设somePayload是组件内的状态变量,当它更新后,effect不会因为它的变化重新执行。等到下一次changeMe触发effect时,你发送的还是旧版本的somePayload,这种数据不一致的问题,往往要到业务逻辑出问题时才会被发现。
未填全依赖数组的隐蔽风险
过期闭包引发逻辑错误
这是最常见的问题。effect里的变量是渲染时的固定快照,依赖没列全的话,后续变量更新后effect也拿不到新值。比如你在effect里计算某个统计值,用到了组件状态total但没把它放进依赖,当total更新后,effect里的计算结果还是基于旧值,直接导致业务逻辑出错。函数引用过期导致意外行为
如果api.send是组件内部定义的函数(或者依赖组件状态的函数),每次渲染它的引用都会变化。如果你没把它放进依赖,effect里调用的始终是旧版本的api.send,函数内部用到的变量也都是旧的,执行结果自然不符合预期。就算是外部导入的工具函数,只要它内部依赖了可变状态,也可能出现类似问题。难以调试的偶发bug
这种问题不会立刻暴露,往往是用户进行了多步操作、状态多次更新后才会显现。比如用户修改了表单内容(somePayload变化),然后触发了changeMe的更新,此时发送的却是旧表单数据——你很难第一时间联想到是依赖数组没写全导致的,排查成本极高。
关于你遇到的循环触发与不必要重渲染
你提到用useCallback包裹后仍出现大量重渲染,大概率是useCallback的依赖没写对,或者包裹的函数本身依赖了太多频繁变化的状态。这时候应该从逻辑层面优化,而非直接跳过依赖校验:
- 如果
api.send是全局不变的工具函数、someUrl是固定常量,确实不需要放进依赖,此时可以用// eslint-disable-next-line react-hooks/exhaustive-deps忽略警告,但要确保这些值真的不会变化。 - 如果
somePayload仅在changeMe变化时需要更新,你可以用useMemo缓存somePayload,让它只在相关依赖变化时更新,这样把它放进effect依赖也不会导致频繁触发。
内容的提问来源于stack exchange,提问作者Electric Coffee

