який є кращим способом мутувати стан Реагувати?


97

Скажімо, у мене є список простих предметів, this.state.listякі я можу потім використовувати для відображення списку дітей. Який тоді правильний спосіб вставити об'єкт у this.state.list?

Нижче - єдиний спосіб, на який я думаю, що це буде працювати, тому що ви не можете мутувати this.stateбезпосередньо, як зазначено в документі.

this._list.push(newObject):
this.setState({list: this._list});

Це мені здається некрасивим. Чи є кращий спосіб?


можливий дублікат Правильної модифікації масивів держави в ReactJS , що вимагає об'єднання
Brigand

Усі ці відповіді стосуються додавання елемента до масиву. Але як бути з видаленням елемента з нього? Або просто повністю скинути масив на новий?
Августин Рідінгер

Відповіді:


165

concat повертає новий масив, так що ви можете це зробити

this.setState({list: this.state.list.concat([newObject])});

інша альтернатива - помічник незмінності React

  var newState = React.addons.update(this.state, {
      list : {
        $push : [newObject]
      }
  });

  this.setState(newState);

6
concatбере масив, тож вам захочеться this.state.list.concat([newObject]).
Софі Альперт

@BenAlpert працює для мене в Chrome, ти кажеш, це нестандартна поведінка?
Купа

6
@Heap Добре, якщо ви передасте не масив до concatнього, він оберне його в масив, але краще додати масив, щоб він був явним: якщо у вас є [[1,2], [3,4]]і хочете додати [5,6]як наступний елемент, вам потрібно зробити .concat([[5,6]])ще Я закінчу [[1,2], [3,4], 5, 6].
Софі Алперт

2
Наскільки я ціную ідею, що стоїть за помічниками незмінність (і я все-таки зможу використовувати її у будь-якому випадку), я Array.concatвпевнено додаю ще одну бібліотеку.
Шон Еркхарт

1
Виклик this.setState зі значенням, отриманим від this.state, призведе до помилок щодо проблем із пакетним оновленням. Дивіться stackoverflow.com/a/41445812/1998186, де посилаються на jsfiddle, що показує проблему, яку ви отримаєте.
NealeU

40

setState () можна викликати функцією в якості параметра:

this.setState((state) => ({ list: state.list.concat(newObj) }))

або в ES5:

this.setState(function(state) {
  return {
   list: state.list.concat(newObj)
  }
})

2
@Arian: React виконає необхідні інструкції щодо мутації DOM, необхідні для надання лише нещодавно доданих елементів. Зважаючи, звичайно, що нещодавно додані елементи не змінюють спосіб відображення попередніх елементів.
Хосе Браун

1
Це фантастична відповідь, і він відчуває себе набагато чистішим, ніж концентрувати масив, просто виконувати поштовх, хоча така думка я здогадуюсь.
Метт Стайлз

2
@Nyalab, чи не слід ви обгортати тіло функції в дужки? Як це зараз у вашому прикладі, дужки після жирової стрілки розпочнуть блок, а не предмет. Щось подібне:this.setState((state) => ({ list: state.list.push(newObj) }))
kumarharsh

3
Як працює цей код? метод push поверне a NUMBER, який буде встановлено на listзмінну
kumarharsh

1
Ви також можете скористатися this.setState((state) => ({ list: [...state.list, newObj] }))
значком


7

З документів про реагування ( https://facebook.github.io/react/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous ):

Оскільки цей.props та this.state може оновлюватися асинхронно, не слід покладатися на їх значення для обчислення наступного стану.

Тому вам слід зробити це замість цього:

this.setState((prevState) => ({
  contacts: prevState.contacts.concat([contact])
}));
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.