两个状态处理函数有何差异?为何表现不一致?
两个React状态更新函数的核心差异
这两个函数的核心区别在于是否遵循React状态的不可变性要求,直接导致了状态更新后的表现完全不同:
第二个函数的问题(直接修改原状态)
setEatenFoodList(prevList => { prevList[index].removingFade = true; return prevList; })
- 这段代码直接修改了原状态数组
prevList里的元素属性,然后返回了原来的数组引用。React判断状态是否变化是基于引用对比的,因为数组引用没改,React会认为状态没有更新,大概率不会触发组件重渲染,你设置的removingFade: true可能不会在UI上体现出来。 - 直接修改原状态是React的反模式,会导致状态突变,后续难以追踪状态变化的轨迹,还可能影响依赖该状态的其他逻辑。
第一个函数的特点(返回新数组,但仍有小瑕疵)
setEatenFoodList(prevList => { const newList = []; for (let i=0 ; i<prevList.length ; i++) { if (i === index){ const editedFood = prevList[i]; editedFood.removingFade = true; newList.push(editedFood) } else { newList.push(prevList[i]) } } return newList; })
- 这段代码创建了一个新数组
newList,把原数组的元素逐个复制进去,修改对应索引的元素属性后加入新数组,最后返回这个新数组。因为数组的引用变了,React能识别到状态变化,会触发组件重渲染,你的UI会更新。 - 不过要注意,这个函数也不是完全符合不可变更新的要求:它直接修改了原数组里的
editedFood对象的属性(因为对象是引用类型),原状态里的对象其实还是被改动了。如果要做到彻底的不可变,应该复制这个对象再修改,比如改成:const editedFood = {...prevList[i], removingFade: true};
总结
- 第二个函数因为返回原数组引用,React不会触发重渲染,状态更新无效;
- 第一个函数返回新数组,能触发重渲染,但修改原对象属性的做法不够严谨,建议改成复制对象的方式实现完全不可变更新。
内容的提问来源于stack exchange,提问作者oussamaZAAM
相关产品推荐
相关产品推荐

