【问题标题】:React JS Update an object from an arrayReact JS 从数组中更新对象
【发布时间】:2021-07-07 05:34:30
【问题描述】:

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

[
  {
    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);
};

有没有更好的方法来做到这一点?

【问题讨论】:

    标签: arrays reactjs state javascript-objects


    【解决方案1】:

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

    尝试这样的做法,将所有内容一直克隆到嵌套的items 属性:

    const handleAddNewItemSubmit = (title, id) => {
      setLists(
        lists.map(list => list.id !== id ? list : ({
          ...list,
          items: [...list.items, { title }]
        })
      );
    };
    

    【讨论】:

    • 看来我必须了解更多关于 React 状态管理的知识,你能推荐任何我应该了解的资源吗?
    • 该状态下没有数组的直接变异,所有的复杂变异都是在拷贝数据上进行的const newData = [...lists];
    • @YvesKipondo 问题出在newData[listIndex].items =newData 是浅拷贝,不是深拷贝。 newData[listIndex] 发生变异是对状态对象的引用,而不是新对象。
    • @vajad57 “避免突变”几乎是我知道你绝对应该遵循的唯一硬性规则。我认为,在状态管理方面没有任何其他方面的重要性接近
    【解决方案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);
    };
    

    在上面的代码中,当你做const newData = [...lists]时,它只是做浅拷贝,即只有顶层引用会不同,但如果有任何嵌套对象,它们将具有与lists相同的引用。

    所以当你做newData[listIndex].items时,你实际上指的是同一个对象,即lists[listIndex].items。由于newData[listIndex].items 是一个数组,而数组又是一个对象,它的引用与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');

    【讨论】:

      猜你喜欢
      • 2019-08-03
      • 1970-01-01
      • 1970-01-01
      • 2022-11-18
      • 2022-01-25
      • 2021-11-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多