Как обновить состояние вложенного массива массива объектов без изменения - PullRequest
0 голосов
/ 29 августа 2018

Я пытаюсь обновить состояние вложенного массива объектов, например, добавить к результатам [0] .rooms [2] -> комнаты цикла -> и добавить к каждому объекту room.sunday.flag

array of results:
results:  [ 
  { dates:
  { weekstart: 2018-08-26T04:00:00.000Z,
    weekend: 2018-09-02T03:59:59.000Z,
    daysofweek: [Array] },
 need: [ '103', '204', '12', '234', '34', '555', '44' ],
 backorder:
  [ '100', '102', '150', '403', '344', '12', '3434', '23', '44' ],
 _id: 5b7b139465c29145d8d69ac2,
 iscurrent: true,
 isnext: false,
 rooms: [ [Object], [Object], [Object], [Object] ],
 user: 5b61b782719613486cdda7ec,
 __v: 9 },

 { dates:
  { weekstart: 2018-09-02T04:00:00.000Z,
    weekend: 2018-09-09T03:59:59.000Z,
    daysofweek: [Array] },
 need: [ '12', '13', '55', '45' ],
 backorder: [ '10', '11', '112' ],
 _id: 5b83fdc500b6b6dc493e9bb8,
 iscurrent: false,
 isnext: true,     rooms: [ [Object], [Object], [Object], 
 [Object] ],
 user: 5b61b782719613486cdda7ec,
 __v: 9 } 
 ]

моя попытка изменить состояние без изменения

   const resultsRooms = [ 
     ...this.state.results[0].rooms ];
        const rooms = resultsRooms.map((room, roomIndex) => 
   {
        room.sunday.flag = true;
   });

   const resultsUpdaye = this.results.forEach((element, index) => {
      if (index === 0) {
            elsment.rooms = rooms;
         }
   });

   this.setState({
            results: resultsUpdaye
   });

любая помощь? что я делаю не так

1 Ответ

0 голосов
/ 29 августа 2018

Ваш resultsRooms.map не так. Прежде всего, он не возвращает объект. Если вы используете функцию со стрелкой и хотите вернуть объект, вы должны заключить его в скобки.

const foo = () => ( { foo: "bar" } );

Если вы этого не сделаете, функция увидит {} как блок тела.

Ваша вторая проблема: map возвращает массив, не выполняет операций с элементами. Так что вы не можете сделать это: room.sunday.flag = true;

Вот рабочая версия:

const rooms = resultsRooms.map((room, roomIndex) => 
   ( { ...room, sunday: {...room["sunday"], flag: true } } )
);

Итак, мы отображаем комнаты, а затем возвращаем объект с расширенным синтаксисом. С ...room мы сохраняем части room, отличные от sunday объекта. С sunday: {...room["sunday"], flag: true } мы сохраняем части sunday, отличные от свойства flag. Кроме того, на самом деле нам не нужно делать копию с:

const resultsRooms = [ 
     ...this.state.results[0].rooms ];

Поскольку мы не изменяем его, с помощью map мы создаем новый массив. Итак, вот последняя версия:

const rooms = results[0].rooms.map((room, roomIndex) => 
   ( { ...room, sunday: {...room["sunday"], flag: true } } )
);

Эта часть в порядке, мы не изменяем состояние, но если вы используете forEach на results, вы изменяете исходные данные. Не делай этого.

Вот краткая и, возможно, более чистая альтернатива без использования forEach.

const newRooms = results[0].rooms.map( room =>
    ( { ...room, sunday: {...room["sunday"], flag: true } } )
  );

const newItem = { ...results[0], rooms: newRooms };
const newResults = Object.assign([], results, { 0: newItem } );

Обновление после комментариев

Я использовал Object.assign здесь, чтобы заменить элемент без изменения исходного массива. При использовании React (также, если вы предпочитаете использовать с React, это также относится и к Redux), мы должны избегать изменения наших данных, а именно нашего состояния. Поэтому, когда вы планируете что-то изменить в состоянии, вы должны делать это надлежащим образом. Ваш вопрос на самом деле указывает на то, что: "без мутирования" Вот почему я использовал Object.assign здесь.

Я мог бы выбрать другие методы, такие как:

const newResults = results.slice();
newResults[ 0 ] = newItem;

или

const newResults = [ ...results ];
newResults[ 0 ] = newItem;

Это нормально только для замены элемента в целом . Что я имею в виду здесь? slice и spread syntax не создают глубокие копии, они просто делают мелкие копии. Если вы измените свойство объекта во вновь созданном массиве, исходный объект также будет видоизменяться. Это также относится к объектам, когда мы меняем вложенные свойства. На самом деле, оригинальный источник - это объекты здесь.

Вот пример массива:

const arr = [
  { id:1, name:"foo" },
  { id:2, name:"bar" },
  { id:3, name:"baz" },
];

и пример элемента, который нужно изменить для индекса 2 (последний элемент здесь);

const newItem = { id: 100, name: "change" };

const newArr = [ ...arr ];
arr[ 2 ] = newItem;

Это нормально, так как здесь мы меняем целый объект. Посмотрим:

const arr = [
  { id:1, name:"foo" },
  { id:2, name:"bar" },
  { id:3, name:"baz" },
];

const newItem = { id: 100, name: "change" };

const newArr = [ ...arr ];
newArr[ 2 ] = newItem;

console.log("new array", newArr );
console.log( "original array", arr );

Оригинал не меняется. Но если мы сделаем это:

newArr[ 2 ].id = 100; // ie, we only want to change the id, right?

Посмотрим:

const arr = [
  { id:1, name:"foo" },
  { id:2, name:"bar" },
  { id:3, name:"baz" },
];

const newArr = [ ...arr ];
newArr[ 2 ].id = 100;

console.log("new array", newArr );
console.log( "original array", arr );

Итак, наш исходный массив также изменился. Мутация! Если вы не измените какое-либо свойство, как это, вы можете выбрать один из трех вариантов. Но если вы поменяете свойство, вам следует подумать о чем-то лучше.

const arr = [
  { id:1, name:"foo" },
  { id:2, name:"bar" },
  { id:3, name:"baz" },
];

const newArr = Object.assign( [], arr, { 2: { ...arr[ 2 ], id: 100 } } );


console.log("new array", newArr );
console.log( "original array", arr );

Duh! :) Может быть, есть лучшие способы сделать это :) В любом случае, будьте очень осторожны с изменением состояния.

Просто с объектом:

const obj = { 
  user: {
    id: 1,
    name: "foo",
  }
};
const newObj = { ...obj }
newObj.user.id = 1000

console.log( "new object", newObj );
console.log( "original object", obj );

Хорошо, этого достаточно для объяснения:)

Спасибо за ответ. Я немного смущен, я должен установить состояние выглядит следующим образом: this.setState ({results: newResults});

Да.

также, что если я хочу изменить состояние всех комнат массива результатов результаты [0], результаты [1], результаты [2] .....

Да ладно, у вас здесь отличный инструмент :) map

const newResults = results.map( item => {
  const newRooms = item.rooms.map( room =>
    ( { ...room, sunday: {...room["sunday"], flag: true } } )
  );
  const newItem = { ...item, rooms: newRooms };

  return newItem;
})

Сначала мы сопоставляем results, для каждого элемента мы сопоставляем rooms и меняем данные, возвращая новый элемент. Таким образом, в конце мы получаем новый массив, в котором все его элементы изменились, но снова без каких-либо изменений.

Я предлагаю немного поиграть с map, filter и, возможно, reduce методами. Также ищите spread syntax или, если вы предпочитаете Object.assign, это плюс.

...