更新一个嵌套对象
考虑下面这种结构的嵌套对象:
js
const [person, setPerson] = useState({
name: 'Niki de Saint Phalle',
artwork: {
title: 'Blue Nana',
city: 'Hamburg',
image: 'https://react.dev/images/docs/scientists/Sd1AgUOm.jpg',
}
});
但是在 React 中,你需要将 state 视为不可变的!为了修改 city 的值,你首先需要创建一个新的 artwork 对象(其中预先填充了上一个 artwork 对象中的数据),然后创建一个新的 person 对象,并使得其中的 artwork 属性指向新创建的 artwork 对象:
js
const nextArtwork = { ...person.artwork, city: 'New Delhi' };
const nextPerson = { ...person, artwork: nextArtwork };
setPerson(nextPerson);
或者,写成一个函数调用:
js
setPerson({
...person, // 复制其它字段的数据
artwork: { // 替换 artwork 字段
...person.artwork, // 复制之前 person.artwork 中的数据
city: 'New Delhi' // 但是将 city 的值替换为 New Delhi!
}
});
这虽然看起来有点冗长,但对于很多情况都能有效地解决问题
下面是常见数组操作的参考表。当你操作 React state 中的数组时,你需要避免使用左列的方法,而首选右列的方法:
| 避免使用 (会改变原始数组) | 推荐使用 (会返回一个新数组) |
|---|---|
| 添加元素 push,unshift concat, | ...arr 展开语法(例子) |
| 删除元素 pop,shift,splice | filter,slice(例子) |
| 替换元素 splice,arri = ... 赋值 | map(例子) |
| 排序 reverse,sort | 先将数组复制一份(例子) |
你应该创建一个 新 数组,其包含了原始数组的所有元素 以及 一个在末尾的新元素。这可以通过很多种方法实现,最简单的一种就是使用 ... 数组展开 语法:
js
setArtists( // 替换 state
[ // 是通过传入一个新数组实现的
...artists, // 新数组包含原数组的所有元素
{ id: nextId++, name: name } // 并在末尾添加了一个新的元素
]
);
对象并不是 真的 位于数组"内部"。可能他们在代码中看起来像是在数组"内部",但其实数组中的每个对象都是这个数组"指向"的一个存储于其它位置的值。这就是当你在处理类似 list0 这样的嵌套字段时需要格外小心的原因。
当你更新一个嵌套的 state 时,你需要从想要更新的地方创建拷贝值,一直这样,直到顶层。