Modification correcte des tableaux d'état dans ReactJS

Je veux ajouter un élément à la fin d'un state tableau, est-ce la bonne façon de le faire?

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

Je crains que la modification du tableau en place avec push puisse causer des problèmes - est-ce sûr?

L'alternative de faire une copie du tableau, et setState cela semble inutile.

247
demandé sur fadedbee 2014-10-08 13:20:37

6 réponses

Les documents React indiquent:

Traite ça.Etat comme si elle était immuable.

Votre {[3] } va muter l'état directement et cela pourrait potentiellement conduire à un code sujet aux erreurs, même si vous "réinitialisez" l'état par la suite. F. ex, cela pourrait conduire à ce que certaines méthodes de cycle de vie comme componentDidUpdate ne se déclenchent pas.

L'approche recommandée dans les versions ultérieures de React consiste à utiliser une fonction updater lors de la modification d'États pour empêcher la course conditions:

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

Le "gaspillage" de mémoire n'est pas un problème comparé aux erreurs que vous pourriez rencontrer en utilisant des modifications d'état non standard.

Syntaxe Alternative pour les versions précédentes de React

Vous pouvez utiliser concat pour obtenir une syntaxe propre car elle renvoie un nouveau tableau:

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

Dans ES6, vous pouvez utiliser l'opérateur Spread :

this.setState({
  arrayvar: [...this.state.arrayvar, newelement]
})
476
répondu David 2018-04-06 13:19:53

Plus facile, si vous utilisez ES6.

initialArray = [1, 2, 3];

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

Nouveau tableau sera [1,2,3,4]

Pour mettre à jour votre état dans React

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

En savoir plus sur la déstructuration des tableaux

90
répondu StateLess 2017-05-16 10:02:30

Le moyen le plus simple avec ES6:

this.setState(prevState => ({
    array: [...prevState.array, newElement]
}))
33
répondu Ridd 2017-08-07 09:13:31

React peut mettre à jour par lots, et donc l'approche correcte est de fournir à setState une fonction qui effectue la mise à jour.

Pour L'addon react update, ce qui suit fonctionnera de manière fiable:

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

Ou pour concat ():

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

Ce qui suit montre ce que https://jsbin.com/mofekakuqi/7/edit?js, sortie comme un exemple de ce qui se passe si vous vous trompez.

L'appel setTimeout () ajoute correctement trois éléments car React ne mettra pas à jour par lots dans un rappel setTimeout (voir https://groups.google.com/d/msg/reactjs/G6pljvpTGX0/0ihYw2zK9dEJ).

Le buggy onClick ajoutera seulement "troisième", mais le fixe, ajoutera F, S et T comme prévu.

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'));
19
répondu NealeU 2017-01-03 14:31:42

Comme @nilgun mentionné dans le commentaire, vous pouvez utiliser les aides react immutabilité . J'ai trouvé que c'était super utile.

À partir des documents:

Simple poussée

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

initialArray est toujours [1, 2, 3].

17
répondu Clarkie 2015-08-27 22:00:42

Ce code fonctionne pour moi:

fetch('http://localhost:8080')
  .then(response => response.json())
  .then(json => {
    this.setState({mystate: this.state.mystate.push.apply(this.state.mystate, json)})
  })
0
répondu Hamid Hosseinpour 2018-09-24 05:55:16