React - 使用setState更新状态中的对象数组

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React - 使用setState更新状态中的对象数组相关的知识,希望对你有一定的参考价值。

我正在制作一个桌子规划器应用程序,可以将客人分配到餐桌上。我在一个名为tabledata的状态下创建了一个对象数组,它将包含如下对象:

    this.state = {
      tabledata: [
        {
          name: "Top Table",
          guests: ["guest1", "guest2", "guest3"]
        },
        {
          name: "Table One",
          guests: ["guest3", "guest4", "guest5"]
        }
      ]
    }

然后我创建了一个拖放界面,客人可以在表之间移动。我试图像这样更新状态:

  updateTableList (tablename, guest) {
    const selectedTableObj = this.state.tabledata.filter((tableObj) => tableObj.name === tablename);
    const otherTableObjs = this.state.tabledata.filter((tableObj) => tableObj.name !== tablename);

    selectedTableObj[0].guests.push(guest);
    const updatedObjectArray = [...otherTableObjs, selectedTableObj];

    this.setState({
      tabledata: [...otherTableObjs, ...selectedTableObj]
    });

  }

这是有效的,但因为我从状态中删除selectedTableObj然后将其添加到数组的末尾我在屏幕上得到了一些时髦的结果。更新后的表始终会显示在页面底部(正如您所期望的那样)。

如何更新对象而不更改其在数组中的位置?

答案

使用Array.findIndex()查找要更新的表的索引。创建一个新的tabledata数组。使用Array.slice()获取更新表之前和之后的项目,并将spread用于新的tabledata数组。使用对象扩展创建一个新的表对象,添加更新的guests数组,并在前面的项之间添加表对象:

代码(未测试):

updateTableList(tablename, guest) {
  this.setState((prevState) => {
    const tableData = prevState.tabledata;
    const selectedTableIndex = tableData.findIndex((tableObj) => tableObj.name === tablename);
    const updatedTable = tableData[selectedTableIndex];

    return {
      tabledata: [
        ...prevState.tabledata.slice(0, selectedTableIndex),
        {
          ...updatedTable,
          guests: [...updatedTable.guests, guest]
        },
        ...prevState.tabledata.slice(selectedTableIndex + 1)
      ]
    };
  });
}
另一答案

selectedTableObj[0].guests.push(guest)直接改变了React不鼓励的状态。

试试这个:

this.setState((prevState) => {
  const newData = [...prevState.tabledata];
  // if you pass in `index` as argument instead of `tablename` then this will not be needed
  const index = prevState.tabledata.findIndex(table => tableObj.name === tablename); 

  newData[index] = {
    ...newData[index],
    guests: newData[index].guests.concat([guest]),
  };
  return { tabledata: newData };
});

您也没有从上一个表中删除guest虚拟机,因此您需要对其进行修改。

另一答案

你可以使用Array.reduce来完成它

let newState = this.state
// let newState = {...this.state} // in case you want everything immutable
newState.tableData = newState.tableData.reduce((acc, table) => 
  if(table.name === tableName) {
    return acc.concat({...table, guests: table.guests.concat(newGuest)})
  } else {
    return acc.concat(table)
  }
)

以上是关于React - 使用setState更新状态中的对象数组的主要内容,如果未能解决你的问题,请参考以下文章

React - 使用setState更新状态中的对象数组

如何知道所有 setState 更新是不是已应用于 React 组件中的状态?

React JS:setState中的previousState在状态更新后不保留先前状态的数据

react setState 回调没有更新状态

setState 没有更新 React 中的设置值 [重复]

用 setState() 更新嵌套的 React 状态属性的最佳选择是啥?