React Hooks useEffect中setInterval操作数组状态非预期增长求解
问题原因
这是React 18开发环境下的预期行为,不是Hooks的Bug:
- 本地开发时默认开启了严格模式(StrictMode),该模式会在开发环境主动调用两次状态更新函数,用于提前排查更新逻辑中存在的副作用问题,生产环境不会触发该逻辑,所以你的静态站点运行正常。
- 你的更新代码存在不符合immutable规范的问题:在
setA的回调函数中直接修改了传入的原状态prev的内部值,第一次调用更新函数就已经修改了原状态的内容,第二次调用时会在已经修改后的值基础上再次+100,最终表现为每秒增加200。
解决方案
不需要使用useReducer,只要修改状态更新逻辑,遵循不修改原状态、先拷贝再修改的原则即可,修改后的代码如下:
定时器部分修改
useEffect(() => { const eff = setInterval(() => { setA((prev) => { // 先完整拷贝二维数组,不改动原prev const newA = prev.map(subArr => [...subArr]) newA[1][0] += 100; console.log("add 100"); return newA; }); }, 1000); return () => clearInterval(eff); }, []);
点击事件逻辑说明
你给出的multiple函数本身没有修改传入的原状态p,而是直接计算生成了全新的二维数组,本身是符合规范的,只需要把多余的展开操作去掉即可(也可以保留,不影响运行):
const multiple = () => { setA((p) => { const newArray = [ [ p[0][0] * p[0][0] + p[0][1] * p[1][0], p[0][0] * p[0][1] + p[0][1] * p[1][1], ], [ p[1][0] * p[0][0] + p[1][1] * p[1][0], p[1][0] * p[0][1] + p[1][1] * p[1][1], ], ]; // newArray本身就是全新数组,不需要再展开生成新数组 return newArray; }); };
修改完成后不管严格模式调用几次更新函数,最终的状态更新结果都是一致的,就会符合你每秒加100的预期。
内容的提问来源于stack exchange,提问作者usa
相关产品推荐
相关产品推荐

