React/React Native中更新useState对象为何两种写法效果不同
问题原因解析
核心原理:React状态的不可变性要求
React的状态设计遵循不可变性原则,要求开发者永远不能直接修改useState返回的状态值,必须创建一个全新的副本,修改副本后再传给状态更新函数。另外在开发模式的严格模式下(现在官方脚手架默认开启),React会冻结useState返回的状态对象,直接修改原状态的操作会被静默阻止或者直接抛出错误。
代码1无法生效的原因
- 你直接对原状态数组
items执行了items[objIndex] = folder的修改操作,属于直接修改原状态的突变行为。在开发模式下items是被冻结的只读对象,这行赋值操作根本不会生效,items的内容还是原来的值。 - 后续你执行
setItems([...items])时,展开的还是未被修改的原状态数组,最终传入setItems的内容和原状态没有差异,自然不会触发预期的更新。
另外注意你代码里的笔误:useState('')初始值设置的是空字符串,调用数组方法findIndex会直接报错,正确的初始值应该是空数组useState([])。
代码2可以正常运行的原因
你先通过const myItems = [...items]创建了原状态数组的完全副本,这个myItems是你自主创建的普通数组,没有被React冻结,属于可写对象。后续修改myItems的元素是完全生效的,最后把修改完成的新数组传给setItems,相当于用全新的状态引用更新,符合React的状态更新规则,所以可以正常运行。
额外补充
遵循不可变性原则除了符合React的更新规则外,还有两个明显优势:
- 避免原状态被意外修改导致的不可预期bug,保证每一次状态快照的稳定性
- React做更新判断时只需要做浅比较(对比引用地址),不需要深度遍历对比内容,性能更高
内容的提问来源于stack exchange,提问作者Jerry seigle
相关产品推荐
相关产品推荐

