React点击时toggle功能失效,控制台输出重复值问题排查
React数组对象Toggle失效、控制台重复输出数值的问题排查与解决
问题原因
- 违反状态不可变性原则:你用
[...oldArr]复制数组,但数组内的对象是引用类型,newArr[0]和原数组的第一个对象指向同一块内存空间,直接修改newArr[0].componentId本质是在修改原状态对象,这不符合React的状态更新规范。 - React严格模式的影响:在开发环境下,React严格模式会两次执行状态更新回调函数来检测副作用。第一次执行时把
componentId改成1,第二次执行时因为引用没断,还是基于原对象(值为0)再次修改,又改回0,最终状态没有变化,控制台就会输出1和0。
修复方案
遵循React状态不可变性要求,修改数组中的对象时,必须创建新的对象实例,而不是直接修改原对象。可以用map方法遍历数组,对目标元素生成新对象:
const { useState } = React; const App = () => { const [Btns, setBtns] = useState([ { componentId: 0 }, { componentId: 0 } ]); return ( <div> <button onClick={() => { setBtns(oldArr => oldArr.map((item, idx) => idx === 0 ? { ...item, componentId: item.componentId === 0 ? 1 : 0 } : item ) ); }} > Button </button> {/* 新增展示,直观验证toggle效果 */} <p>第一个按钮的componentId:{Btns[0].componentId}</p> </div> ); }; ReactDOM.render(<App />, document.getElementById("react"));
修复说明
- 用
map遍历数组,对需要修改的元素(索引0),通过扩展运算符{...item}创建新对象,再覆盖componentId值,完全脱离对原状态对象的引用。 - 即使严格模式下两次执行更新函数,每次都是基于上一次的正确状态计算新值,最终状态会正常切换,控制台也不会出现重复的回滚输出。
内容的提问来源于stack exchange,提问作者s.kuznetsov
相关产品推荐
相关产品推荐

