web-dev-qa-db-fra.com

Pourquoi l'appel de la méthode react setState ne modifie pas l'état immédiatement?

Je lis la section Forms de la documentation reactjs et viens d'essayer ce code pour démontrer l'utilisation de onChange ( JSBIN ).

var React= require('react');

var ControlledForm= React.createClass({
    getInitialState: function() {
        return {
            value: "initial value"
        };
    },

    handleChange: function(event) {
        console.log(this.state.value);
        this.setState({value: event.target.value});
        console.log(this.state.value);

    },

    render: function() {
        return (
            <input type="text" value={this.state.value} onChange={this.handleChange}/>
        );
    }
});

React.render(
    <ControlledForm/>,
  document.getElementById('mount')
);

Lorsque je mets à jour la valeur <input/> dans le navigateur, le deuxième console.log dans le rappel handleChange imprime la même value que le premier console.log. Pourquoi ne puis-je pas voir le résultat de this.setState({value: event.target.value}) dans l'étendue du rappel handleChange?

232
tarrsalah

De React's documentation :

setState() ne mute pas immédiatement this.state mais crée un en attente de transition d'état. Accéder à this.state après avoir appelé cette méthode peut potentiellement renvoyer la valeur existante. Il n'y a pas garantie de fonctionnement synchrone des appels à setState et les appels peuvent être groupé pour des gains de performance.

Si vous souhaitez qu'une fonction soit exécutée après le changement d'état, transmettez-la sous forme de rappel.

this.setState({value: event.target.value}, function () {
    console.log(this.state.value);
});
484
Michael Parker

Comme indiqué dans la documentation de React, rien ne garantit que setState sera déclenché de manière synchrone. Votre console.log peut donc renvoyer l'état avant sa mise à jour.

Michael Parker mentionne avoir passé un rappel dans la setState. Une autre façon de gérer la logique après le changement d'état consiste à utiliser la méthode componentDidUpdate lifecycle, méthode recommandée dans la documentation de React.

En règle générale, nous vous recommandons d’utiliser ComponentDidUpdate () pour une telle logique.

Ceci est particulièrement utile lorsqu'il peut y avoir plusieurs déclenchements successifs de setState et que vous souhaitez activer la même fonction après chaque changement d'état. Plutôt que d'ajouter un rappel à chaque setState, vous pouvez placer la fonction à l'intérieur de la componentDidUpdate, avec une logique spécifique à l'intérieur si nécessaire.

// example
componentDidUpdate(prevProps, prevState) {
  if (this.state.value > prevState.value) {
    this.foo();  
  }
}
39
Yo Wakita

Vous pouvez essayer d’utiliser ES7 async/wait. Par exemple, en utilisant votre exemple:

handleChange: async function(event) {
    console.log(this.state.value);
    await this.setState({value: event.target.value});
    console.log(this.state.value);
}
5
black

Surveillez les méthodes de cycle de vie de réaction!

J'ai travaillé pendant plusieurs heures pour savoir que getDerivedStateFromProps sera appelé après chaque setState()

????

3
osrpt

La syntaxe async-await fonctionne parfaitement pour quelque chose comme ce qui suit ...

changeStateFunction = () => {
  // Some Worker..

  this.setState((prevState) => ({
  year: funcHandleYear(),
  month: funcHandleMonth()
}));

goNextMonth = async () => {
  await this.changeStateFunction();
  const history = createBrowserHistory();
  history.Push(`/calendar?year=${this.state.year}&month=${this.state.month}`);
}

goPrevMonth = async () => {
  await this.changeStateFunction();
  const history = createBrowserHistory();
  history.Push(`/calendar?year=${this.state.year}&month=${this.state.month}`);
}
0
Ritwik

Mettre simplement - this.setState ({data: value}) est de nature asynchrone, ce qui signifie qu’il sort de la pile d’appels et ne revient dans la pile d’appels que s’il est résolu.

Veuillez lire sur Event Loop pour avoir une image claire de la nature asynchrone dans JS et des raisons pour lesquelles la mise à jour prend du temps -

https://medium.com/front-end-weekly/javascript-event-loop-explained-4cd26af121d4

Par conséquent -

    this.setState({data:value});
    console.log(this.state.data); // will give undefined or unupdated value

car il faut du temps pour mettre à jour. Pour réaliser le processus ci-dessus -

    this.setState({data:value},function () {
     console.log(this.state.data);
    });
0
Vishal Bisht