Правильная модификация массивов состояний в ReactJS

Я хочу добавить элемент в конец массива state, это правильный способ сделать это?

this.state.arrayvar.push(newelement);
this.setState({arrayvar:this.state.arrayvar});

Я обеспокоен тем, что изменение массива на месте с помощью push может вызвать проблемы - безопасно?

Альтернатива создания копии массива и setState ing, которая кажется расточительной.

Ответ 1

Документы React говорят:

Относитесь к этому состоянию как к неизменному.

Ваше push будет напрямую изменять состояние, что потенциально может привести к появлению кода, подверженного ошибкам, даже если впоследствии вы "сбрасываете" состояние снова. F.ex, это может привести к тому, что некоторые методы жизненного цикла, такие как componentDidUpdate сработают.

Рекомендуемый подход в более поздних версиях React заключается в использовании функции обновления при изменении состояний для предотвращения состояний гонки:

this.setState(prevState => ({
  arrayvar: [...prevState.arrayvar, newelement]
}))

"Трата" памяти не является проблемой по сравнению с ошибками, с которыми вы можете столкнуться при нестандартных модификациях состояния.

Альтернативный синтаксис для более ранних версий React

Вы можете использовать concat для получения чистого синтаксиса, так как он возвращает новый массив:

this.setState({ 
  arrayvar: this.state.arrayvar.concat([newelement])
})

В ES6 вы можете использовать Spread Operator:

this.setState({
  arrayvar: [...this.state.arrayvar, newelement]
})

Ответ 2

ES6 всего, если вы используете ES6.

initialArray = [1, 2, 3];

newArray = [ ...initialArray, 4 ]; // --> [1,2,3,4]

Новый массив будет [1,2,3,4]

обновить свое состояние в React

this.setState({
         arrayvar:[...this.state.arrayvar, newelement]
       });

Узнайте больше о деструктуризации массива

Ответ 3

Самый простой способ с ES6:

this.setState(prevState => ({
    array: [...prevState.array, newElement]
}))

Ответ 4

React может пакетно обновлять, и поэтому правильный подход заключается в предоставлении setState с функцией, которая выполняет обновление.

Для дополнения обновления React будет выполнено следующее:

this.setState( (state) => update(state, {array: {$push: [4]}}) );

или для concat():

this.setState( (state) => {
    state.array = state.array.concat([4]);
    return state;
});

Ниже показано, что https://jsbin.com/mofekakuqi/7/edit?js,output как пример того, что произойдет, если вы ошибетесь.

Приведение setTimeout() правильно добавляет три элемента, потому что React не будет выполнять пакетные обновления в обратном вызове setTimeout (см. https://groups.google.com/d/msg/reactjs/G6pljvpTGX0/0ihYw2zK9dEJ).

Багги onClick будут добавлять только "Третий", но фиксированный, добавит F, S и T, как ожидалось.

class List extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      array: []
    }

    setTimeout(this.addSome, 500);
  }

  addSome = () => {
      this.setState(
        update(this.state, {array: {$push: ["First"]}}));
      this.setState(
        update(this.state, {array: {$push: ["Second"]}}));
      this.setState(
        update(this.state, {array: {$push: ["Third"]}}));
    };

  addSomeFixed = () => {
      this.setState( (state) => 
        update(state, {array: {$push: ["F"]}}));
      this.setState( (state) => 
        update(state, {array: {$push: ["S"]}}));
      this.setState( (state) => 
        update(state, {array: {$push: ["T"]}}));
    };



  render() {

    const list = this.state.array.map((item, i) => {
      return <li key={i}>{item}</li>
    });
       console.log(this.state);

    return (
      <div className='list'>
        <button onClick={this.addSome}>add three</button>
        <button onClick={this.addSomeFixed}>add three (fixed)</button>
        <ul>
        {list}
        </ul>
      </div>
    );
  }
};


ReactDOM.render(<List />, document.getElementById('app'));

Ответ 5

Как упоминается в примечании @nilgun, вы можете использовать помощники по неизменности. Я нашел, что это очень полезно.

Из документов:

Простой push

var initialArray = [1, 2, 3];
var newArray = update(initialArray, {$push: [4]}); // => [1, 2, 3, 4]

initialArray все еще [1, 2, 3].

Ответ 6

Если вы хотите использовать push, вы можете сделать что-то вроде этого:

// wrong because push modify the array directly
this.setState(prevState => ({
  arrayvar: prevState.arrayvar.push(someElemet) && prevState.arrayvar,
}));

Лучшим решением, конечно, является предотвращение мутации с помощью concat, slice или spread.

Подробнее см. видеоурок.

Ответ 7

this.setState({
  arrayvar: [...this.state.arrayvar, ...newelement]
})

Ответ 8

Этот код работает для меня:

fetch('http://localhost:8080')
  .then(response => response.json())
  .then(json => {
    this.setState({mystate: this.state.mystate.push.apply(this.state.mystate, json)})
  })