1

我的反应状态中有一组对象。

[
  {
    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 handleAddNewItemSubmit = (title, id) => {
  const listIndex = lists.findIndex((list) => list.id === id);

  const newData = [...lists];

  newData[listIndex].items = [...newData[listIndex].items, { title }];

  setLists(newData);
};

有一个更好的方法吗?

4

2 回答 2

2

你正在改变现有的状态(特别是一个数组对象 - 例如lists[0]),这在 React 中永远不应该这样做。你正在做的事情可能奏效,但这不是一个好方法。

尝试这样的事情,将所有内容克隆嵌套items属性:

const handleAddNewItemSubmit = (title, id) => {
  setLists(
    lists.map(list => list.id !== id ? list : ({
      ...list,
      items: [...list.items, { title }]
    })
  );
};
于 2021-04-12T05:55:31.983 回答
1
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');

于 2021-04-12T06:07:30.263 回答