const handleAddNewItemSubmit = (title, id) => {
const listIndex = lists.findIndex((list) => list.id === id);
const newData = [...lists];
newData[listIndex].items = [...newData[listIndex].items, { title }];
setLists(newData);
};
在上面的代码中,当你这样做const newData = [...lists]时只是做浅拷贝,即只有顶级引用会不同,但如果有任何嵌套对象,它们将具有与 of 相同的引用lists。
因此,当newData[listIndex].items您实际上指的是同一个对象时,即lists[listIndex].items. 因为newData[listIndex].items是一个数组,而它又是一个对象,所以它具有与 of 相同的引用lists[listIndex].items。
所以,最终你最终会改变状态。为了避免这种情况,我们可以用不同的方式进行状态更新
const handleAddNewItemSubmit = (title, id) => {
setLists(oldLists => oldLists.map(list =>
list.id === id ? ({
...list,
items: [...list.items, { title }]
}) : list))
}
下面我模拟了两个示例,一个改变顶级对象,另一个改变扩展后的嵌套对象。
let lists = [
{
id: 'd8t4gf',
title: 'Working on',
items: [{ title: 'Item 1' }, { title: 'Item 2' }, { title: 'Item 3' }],
},
{
id: '8jy8g',
title: 'Done',
items: [{ title: 'Item 1' }, { title: 'Item 2' }],
},
];
const addNewTitleOnTopLevel = (title) => {
const newData = [...lists];
newData.push({id: '123', title});
//Since doing `[...lists]` will do a shallow copy, the lengths will be different;
console.log(newData.length, lists.length);
//The objects are different so, it'll be false.
console.log(newData === lists);
}
const addNewTitleInnerItems = (title, id) => {
const listIndex = lists.findIndex((list) => list.id === id);
const newData = [...lists];
newData[listIndex].items = [newData[listIndex].items, {title}]
//Since `newData[listIndex].items` & `lists[listIndex].items`
//are pointing to same references, their length will be same
console.log(newData[listIndex].items.length, lists[listIndex].items.length);
//To know if they both are same or not
console.log(newData[listIndex].items === lists[listIndex].items);
}
addNewTitleOnTopLevel("test");
addNewTitleInnerItems("test", '8jy8g');