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

Posted

技术标签:

【中文标题】React - 使用 setState 更新状态中的对象数组【英文标题】:React - updating an object array in the state with setState 【发布时间】:2018-10-14 23:31:47 【问题描述】:

我正在开发一个餐桌规划器应用程序,可以将客人分配到餐桌。 我在名为 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 然后将其添加到数组的末尾,所以我在屏幕上得到了一些时髦的结果。更新后的表格始终位于页面底部(如您所料)。

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

【问题讨论】:

【参考方案1】:

使用Array.findIndex() 查找要更新的表的索引。创建一个新的tabledata 数组。使用Array.slice()获取更新表前后的项目,spread将它们放入新的tabledata数组中。使用object spread新建一个table对象,添加更新后的guests数组,在之前的item之间添加table对象:

代码(未测试):

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)
      ]
    ;
  );

【讨论】:

我想我最喜欢这个答案。看到这段代码让我想起了我看到 Wes Bos 在我做的一门课程中像这样更新状态。我真的应该记得的。仅供参考 - 我测试了你的代码,里面有几个错别字。 tabledata.findIndex 应该是 tableData.findIndex 和 tabledata[selectedTableIndex] 相同。您能否用这些更新您的答案,因为它真的可能对其他人有所帮助,因为我怀疑这是 React 中相对新手的常见问题。谢谢大家的帮助。【参考方案2】:

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 ;
);

您也没有从之前的表中删除来宾,因此您需要对此进行修改。

【讨论】:

【参考方案3】:

你可以用 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 中的子级

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

React setState 没有得到更新

React Stateful Class Component:使用“this.setState”更新状态的属性,不起作用。没有错误。状态不变

react setState 回调没有更新状态