React - обновление массива объектов в состоянии с помощью setState - PullRequest
0 голосов
/ 04 мая 2018

Я работаю над приложением планировщика стола, где гости могут быть назначены на обеденные столы. Я создал массив объектов в состоянии с именем 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 из состояния, а затем добавляю его в конец массива, я получаю несколько забавных результатов на экране. Обновленная таблица всегда идет вниз страницы (как и следовало ожидать).

Как обновить объект, не меняя его положение в массиве?

Ответы [ 3 ]

0 голосов
/ 04 мая 2018

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

Вы также не удалили гостя из предыдущей таблицы, поэтому вам нужно изменить его.

0 голосов
/ 04 мая 2018

Вы можете сделать это с 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)
  }
)
0 голосов
/ 04 мая 2018

Найдите индекс таблицы, которую вы хотите обновить, используя Array.findIndex(). Создайте новый массив tabledata. Используйте Array.slice(), чтобы получить элементы до и после обновленной таблицы, и распределите их в новый массив 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)
      ]
    };
  });
}
...