Que se passe-t-il lorsque vous utilisez this.setState plusieurs fois dans le composant React?


102

Je voulais vérifier ce qui se passe lorsque vous utilisez this.setState plusieurs fois (2 fois pour le plaisir de la discussion). Je pensais que le composant serait rendu deux fois mais apparemment il n'est rendu qu'une seule fois. Une autre attente que j'avais était que peut-être le deuxième appel à setState passera au premier, mais vous l'avez deviné - a bien fonctionné.

Lien vers un JSfiddle

var Hello = React.createClass({
  render: function() {
    return (
      <div>
        <div>Hello {this.props.name}</div>
        <CheckBox />
      </div>
    );
  }
});

var CheckBox = React.createClass({
  getInitialState: function() {
    return {
      alex: 0
    };
  },

  handleChange: function(event) {
    this.setState({
      value: event.target.value
    });
    this.setState({
      alex: 5
    });
  },

  render: function() {
    alert('render');
    return (
      <div>
        <label htmlFor="alex">Alex</label>
        <input type="checkbox" onChange={this.handleChange} name="alex" />
        <div>{this.state.alex}</div>
      </div>
    );
  }
});

ReactDOM.render(
  <Hello name="World" />,
  document.getElementById('container')
);

Comme vous le verrez, une alerte qui dit «rendu» apparaît sur chaque rendu.

Avez-vous une explication pour expliquer pourquoi cela a fonctionné correctement?


2
React est assez intelligent et ne rendra de nouveau que lorsque l'état requis pour le rendu est modifié. Dans votre méthode de rendu, vous n'utilisez que this.state.alex- que se passe-t-il si vous ajoutez un élément qui dépend this.state.valueégalement?
Martin Wedvich

1
@MartinWedvich Il se cassera au cas où j'en dépendrais. Pour cela, vous avez la méthode 'getInitialState' - pour définir les valeurs par défaut afin que votre application ne s'arrête pas.
alex sous

Réponses:


117

Les lots React indiquent les mises à jour qui se produisent dans les gestionnaires d'événements et les méthodes de cycle de vie. Ainsi, si vous mettez à jour l'état plusieurs fois dans un <div onClick />gestionnaire, React attendra la fin de la gestion des événements avant de re-rendre.

Pour être clair, cela ne fonctionne que dans les gestionnaires d'événements synthétiques contrôlés par React et les méthodes de cycle de vie. Les mises à jour d'état ne sont pas regroupées dans AJAX et les setTimeoutgestionnaires d'événements, par exemple.


1
Merci, ça a du sens, une idée comment ça se fait dans les coulisses?
alex sous

13
Étant donné que React contrôle entièrement les gestionnaires d'événements synthétiques (comme <div onClick />) et les méthodes de cycle de vie des composants, il sait qu'il peut modifier en toute sécurité le comportement de setStatependant la durée de l'appel aux mises à jour d'état par lots et attendre le vidage. Dans un AJAX ou un setTimeoutgestionnaire en revanche, React n'a aucun moyen de savoir quand notre gestionnaire a fini de s'exécuter. Techniquement, React met en file d'attente les mises à jour d'état dans les deux cas, mais vide immédiatement en dehors d'un gestionnaire contrôlé par React.
Chris Gaudreau

1
@neurosnap Je ne pense pas que la documentation donne beaucoup de détails à ce sujet. Il est mentionné de manière abstraite dans la section State and Lifecycle et dans la documentation setState . Consultez le code de ReactDefaultBatchingStrategy , qui est actuellement la seule stratégie de traitement par lots officielle.
Chris Gaudreau

2
@BenjaminToueg Je crois que vous pouvez utiliser ReactDOM.unstable_batchedUpdates(function)pour effectuer des lots en setStatedehors des gestionnaires d'événements React. Comme son nom l'indique, vous annulerez votre garantie.
Chris Gaudreau


33

La méthode setState () ne met pas immédiatement à jour l'état du composant, elle met simplement la mise à jour dans une file d'attente pour être traitée ultérieurement. React peut regrouper plusieurs demandes de mise à jour pour rendre le rendu plus efficace. Pour cette raison, des précautions particulières doivent être prises lorsque vous essayez de mettre à jour l'état en fonction de l'état précédent du composant.

Par exemple, le code suivant incrémentera uniquement l'attribut de valeur d'état de 1 même s'il a été appelé 4 fois:

 class Counter extends React.Component{
   constructor(props){
     super(props)
    //initial state set up
     this.state = {value:0}
   }
   componentDidMount(){
    //updating state
    this.setState({value:this.state.value+1})
    this.setState({value:this.state.value+1})
    this.setState({value:this.state.value+1})
    this.setState({value:this.state.value+1})
   }
   render(){
    return <div>Message:{this.state.value}</div>
   }
}

Afin d'utiliser un état après sa mise à jour, faites toute la logique dans l'argument de rappel:

//this.state.count is originally 0
this.setState({count:42}, () => {
  console.log(this.state.count)
//outputs 42
})

La méthode setState (updater, [callback]) peut prendre une fonction de mise à jour comme premier argument pour mettre à jour l'état en fonction de l'état et des propriétés précédents. La valeur de retour de la fonction de mise à jour sera fusionnée de manière superficielle avec l'état précédent du composant. La méthode met à jour l'état de manière asynchrone, il existe donc un rappel d'option qui sera appelé une fois que l'état a terminé la mise à jour complète.

Exemple:

this.setState((prevState, props) => { 
return {attribute:"value"}
})

Voici un exemple de mise à jour de l'état en fonction de l'état précédent:

    class Counter extends React.Component{
      constructor(props) {
        super(props)
    //initial state set up
        this.state = {message:"initial message"}
    }
      componentDidMount() {
    //updating state
        this.setState((prevState, props) => {
          return {message: prevState.message + '!'}
        })
     }
     render(){
       return <div>Message:{this.state.message}</div>
     }
  }

Ah, je ne connaissais pas le setState(updater,[callback]), c'est comme un Object.assignmerci moins bavard pour ça!
AJ Venturella

1
@Biboswan, salut, je suis nouveau sur React et je voulais vous demander qu'il est vrai que les quatre setStates de la méthode CompountDidMount sont fusionnés et SEUL LE DERNIER setState sera exécuté mais les 3 autres seront ignorés?
Dickens
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.