state 中可以保存任意类型的 JavaScript 值,包括对象。但是,你不应该直接修改存放在 React state 中的对象。相反,当你想要更新一个对象时,你需要创建一个新的对象(或者将其拷贝一份),然后将 state 更新为此对象。
你将会学习到
如何正确地更新 React state 中的对象
如何在不产生 mutation 的情况下更新一个嵌套对象
什么是不可变性(immutability),以及如何不破坏它
如何使用 Immer 使复制对象不那么繁琐
什么是 mutation?
你可以在 state 中存放任意类型的 JavaScript 值。
const [x, setX] = useState(0);
到目前为止,你已经尝试过在 state 中存放数字、字符串和布尔值,这些类型的值在 JavaScript 中是不可变(immutable)的,这意味着它们不能被改变或是只读的。你可以通过替换它们的值以触发一次重新渲染。
setX(5);
state x 从 0 变为 5,但是数字 0 本身并没有发生改变。在 JavaScript 中,无法对内置的原始值,如数字、字符串和布尔值,进行任何更改。
现在考虑 state 中存放对象的情况:
const [position, setPosition] = useState({ x: 0, y: 0 });
从技术上来讲,可以改变对象自身的内容。当你这样做时,就制造了一个 mutation:
position.x = 5;
然而,虽然严格来说 React state 中存放的对象是可变的,但你应该像处理数字、布尔值、字符串一样将它们视为不可变的。因此你应该替换它们的值,而不是对它们进行修改。
将 state 视为只读的
换句话说,你应该 把所有存放在 state 中的 JavaScript 对象都视为只读的。
在下面的例子中,我们用一个存放在 state 中的对象来表示指针当前的位置。当你在预览区触摸或移动光标时,红色的点本应移动。但是实际上红点仍停留在原处: