web-dev-qa-db-fra.com

Modification correcte des tableaux d’états dans ReactJS

Je veux ajouter un élément à la fin d'un tableau state, 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 sur place avec Push puisse causer des problèmes - est-ce sûr?

L'alternative consistant à créer une copie du tableau et à setStateing semble inutile.

292
fadedbee

Les documents React dit:

Traitez cet Etat comme s'il était immuable.

Votre Push mutera l'état directement et cela pourrait potentiellement conduire à un code source d'erreurs, même si vous "réinitialisez" l'état ultérieurement. F.ex, certaines méthodes de cycle de vie telles que 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 afin d'éviter les conditions de concurrence:

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

La "perte" 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]
})
581
David Hellsing

Le plus facile, si vous utilisez ES6.

initialArray = [1, 2, 3];

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

Le nouveau tableau sera [1,2,3,4] 

mettre à jour votre état dans React

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

En savoir plus sur la déstructuration des tableaux

110
StateLess

La manière la plus simple avec ES6:

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

React peut effectuer des mises à jour par lots, et la bonne approche consiste donc à fournir à setState une fonction qui effectue la mise à jour.

Pour le complément de mise à jour de React, 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,output comme exemple de ce qui se passe si vous vous trompez.

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

Le buggy onClick ajoutera seulement "Troisième", mais celui corrigé 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'));
21
NealeU

Comme @nilgun mentionné dans le commentaire, vous pouvez utiliser les aides réagir immutabilité J'ai trouvé cela très utile.

De la docs:

Simple Push

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

(initialArray est toujours [1, 2, 3].} _

17
Clarkie

Vous pouvez utiliser cette méthode : [tableau destructuring]

this.setState(prevState => {
    return {
        arrayData: [...prevState.arrayData, newElement]
    }
});

Réagissez avec la documentation: ne modifiez jamais cet état directement. Comme David Hellsing a expliqué dans sa réponse : appeler ensuite setState () peut remplacer la mutation que vous avez effectuée. Traitez cet état comme s'il était immuable.

1
Hsaidooo
this.setState({
  arrayvar: [...this.state.arrayvar, ...newelement]
})
0
M.Samiei