React Recoil的state对象是否为静默不可变?嵌套修改为何失效?
核心原理说明
- 浅拷贝仅作用于对象第一层
你代码中写的const newState = { ...oldState }是典型的浅拷贝操作,只会对oldState的第一层属性做值复制,当属性值是引用类型(比如你示例里的dog对象)时,拷贝的只是内存地址,也就是说newState.dog和oldState.dog指向的是内存中完全相同的对象。 - 对象被冻结是赋值静默失败的直接原因
Recoil以及多数遵循不可变规范的React状态库(包括部分场景下的原生React useState),为了强制开发者遵守不可变更新规则,会对返回的状态对象执行Object.freeze()冻结处理。被冻结的对象无法修改、新增、删除属性,在非严格模式下这类修改操作会直接静默失败,不会抛出任何错误提示。
而Chrome开发者工具中,赋值表达式newState.dog.paw = true的返回值默认就是你写的右值true,和实际是否赋值成功没有关联,所以才会出现“操作返回成功但属性值没有变化”的错觉。你可以通过执行Object.isFrozen(newState.dog)验证,返回true即可确认对象被冻结。 - 你的解决方案的生效逻辑
newState.dog = {...newState.dog, paw:true}的写法,是新生成了一个未被冻结的dog对象,再给浅拷贝后的newState的第一层dog属性赋值这个新对象,既符合不可变更新的要求,也避开了修改冻结对象的限制,状态库也能正常检测到对象引用的变化触发更新。
内容的提问来源于stack exchange,提问作者JKJ
相关产品推荐
相关产品推荐

