空依赖数组是闭包陷阱的典型信号,effect中变量被冻结为初始值,导致状态更新后副作用仍使用旧值,如定时器读取过期state、请求发送旧id、回调打印陈旧数据。
看 useeffect 依赖数组是否为空
空依赖数组([])是闭包陷阱最典型的信号。它意味着 effect 只在组件挂载时运行一次,内部所有变量(包括 state 和 props)都会被“冻结”为初始值。
比如:
- isPaused 初始为 false,但点击按钮后变成 true,定时器里仍读到 false;
- userId 已更新,但 fetchUser(userId) 仍发的是旧 id 的请求;
- formData 已多次修改,但 setTimeout 里取到的永远是第一次渲染时的空对象。
观察状态变化后逻辑是否“无反应”
UI 显示正确,但副作用行为没同步更新,说明函数体里用的不是最新状态:
- 按钮文字切换了,但数据还在继续轮询;
- 输入框内容变了,但自动保存提交的仍是老数据;
- 列表项被删除,但事件监听器里打印的还是原数组长度或旧元素。
在回调中打印状态值验证“陈旧性”
直接在 setInterval、addEventListener 或 Promise 回调里加 console.log(state),和组件顶层的 console.log(state) 对比:
如果顶层日志随交互实时变化,而回调里的始终不变——基本可以断定是闭包捕获了旧值。
本文档主要讲述的是React Native For Android 源码编译;希望对大家会有帮助;感兴趣的朋友可以过来看看
注意:不要只看 console.log 的输出时机,要对比**同一操作前后两处日志的值是否一致**。
检查是否误把状态当“参数”传进异步逻辑
常见错误写法:
- 在
useEffect(() => { setTimeout(() => setCount(count + 1), 1000) }, [])中直接用了 count; - 在
document.addEventListener('click', () => console.log(isShown))里用了 isShown; - 在
fetch().then(() => setState(prev => ({ ...prev, loaded: true }))外层还依赖了其他 state,却没声明进依赖数组。
这些场景下,变量不是“动态读取”,而是“快照式捕获”。根源不在 state 本身,而在函数创建时绑定的词法环境。










