useEffect回调使用未加入依赖数组的state变量,是否会引发数据不一致?
useEffect依赖数组未包含用到的状态变量,会引发数据不一致吗?
针对你给出的代码场景,先给出明确结论:当前同步执行的逻辑下不会出现数据不一致,但写法存在潜在风险,如果加入异步逻辑就会出问题。
你的代码执行逻辑拆解
先看这段代码:
const [first, set_first] = useState(false); const [is_mobile, set_is_mobile] = useState(false); useEffect(() => { if (!first) { window.scrollBy({ top: is_mobile ? -180 : -195 }); } }, [first]);
具体执行流程:
- 初始渲染:
first=false、is_mobile=false,useEffect触发,执行滚动-195。 - 修改
is_mobile为true:组件重新渲染,但first没变化,useEffect依赖数组没更新,所以不执行回调,但此时新的回调已经捕获了is_mobile=true。 - 修改
first为true:组件重新渲染,first变化触发useEffect,但回调里first=true不满足if(!first),不执行滚动。 - 再把
first改回false:组件重新渲染,first变化触发useEffect,此时回调用的是最新的is_mobile=true,执行滚动-180。
这种情况下,first变化时执行的回调始终是当前渲染时生成的,会捕获最新的is_mobile值,所以不会出现数据不一致。
什么时候会踩坑?
如果useEffect回调里加入异步操作(比如定时器、API请求),闭包的特性就会导致捕获旧状态的问题:
const [first, set_first] = useState(false); const [is_mobile, set_is_mobile] = useState(false); useEffect(() => { if (!first) { // 模拟异步操作 setTimeout(() => { window.scrollBy({ top: is_mobile ? -180 : -195 }); }, 1000); } }, [first]);
执行流程:
- 初始渲染后,
useEffect触发,定时器捕获is_mobile=false。 - 立刻把
is_mobile改成true,组件重新渲染,但first没变化,useEffect不触发,旧定时器还在跑。 - 1秒后定时器执行,用的还是旧的
is_mobile=false,滚动距离错误,出现数据不一致。
正确写法
不管有没有异步逻辑,都应该把回调里用到的所有状态/变量加入依赖数组,从根源避免闭包问题:
useEffect(() => { if (!first) { window.scrollBy({ top: is_mobile ? -180 : -195 }); } }, [first, is_mobile]);
这样,只要first或is_mobile变化,都会触发useEffect执行,确保回调始终用最新的状态值。
内容的提问来源于stack exchange,提问作者Bear Bile Farming is Torture
相关产品推荐
相关产品推荐

