如何在 React 中正确地处理 useEffect 的依赖数组以避免闭包陷阱?
如何在 React 中正确地处理 useEffect 的依赖数组以避免闭包陷阱?
在 React 的 useEffect Hook 中,如果依赖数组未正确包含所有在 effect 中使用的响应式值(如状态、属性或来自父组件的回调函数),就会导致闭包陷阱——即 effect 内部使用的是过时的变量值。
正确做法:
-
完整声明依赖:将 effect 中使用的所有外部变量都加入依赖数组。
const [count, setCount] = useState(0); const [name, setName] = useState(''); useEffect(() => { document.title = `${name} clicked ${count} times`; }, [name, count]); // 必须同时包含 name 和 count -
使用函数式更新:当新状态依赖于旧状态时,使用函数式 setState 避免依赖旧值。
// 错误:依赖缺失 useEffect(() => { const id = setInterval(() => { setCount(count + 1); // 闭包陷阱:count 始终是初始值 }, 1000); return () => clearInterval(id); }, []); // 缺少 count 依赖 // 正确:函数式更新 useEffect(() => { const id = setInterval(() => { setCount(c => c + 1); // 始终使用最新状态 }, 1000); return () => clearInterval(id); }, []); // 无需 count 依赖 -
使用 useCallback/useMemo 保持引用稳定:
// 父组件传递的回调函数 const handleClick = useCallback(() => { console.log(count); }, [count]); // 确保引用仅在 count 变化时更新 // 子组件 useEffect(() => { handleClick(); }, [handleClick]); // 依赖稳定的回调引用 -
使用 ESLint 插件:启用
react-hooks/exhaustive-deps规则自动检测依赖缺失。
常见误区:
- ❌ 手动"优化"依赖数组(如故意省略依赖)
- ❌ 在依赖数组中使用非响应式值(如普通变量)
- ❌ 通过 useRef 绕过依赖检查(应优先考虑重构逻辑)
通过严格遵守依赖规则,可以确保 effect 始终基于最新数据执行,避免难以调试的状态不一致问题。

发表评论 (审核通过后显示评论):