web-dev-qa-db-fra.com

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

Ok, je vais essayer de faire ça rapidement car ça DEVRAIT être une solution facile ...

J'ai lu un tas de questions similaires et la réponse semble assez évidente. Rien que je n'aurais jamais à chercher en premier lieu! Mais ... j'ai une erreur que je n'arrive pas à comprendre comment réparer ou pourquoi cela se produit.

Comme suit:

class NightlifeTypes extends Component {
constructor(props) {
    super(props);

    this.state = {
        barClubLounge: false,
        seeTheTown: true,
        eventsEntertainment: true,
        familyFriendlyOnly: false
    }
    this.handleOnChange = this.handleOnChange.bind(this);
}

handleOnChange = (event) => {   
    if(event.target.className == "barClubLounge") {
        this.setState({barClubLounge: event.target.checked});
        console.log(event.target.checked)
        console.log(this.state.barClubLounge)
    }
}

render() {
    return (
        <input className="barClubLounge" type='checkbox' onChange={this.handleOnChange} checked={this.state.barClubLounge}/>
    )
}

Plus de code entoure cela, mais c'est là que réside mon problème. Devrait fonctionner, non?

J'ai également essayé ceci:

handleOnChange = (event) => {   
if(event.target.className == "barClubLounge") {
    this.setState({barClubLounge: !this.state.barClubLounge});
    console.log(event.target.checked)
    console.log(this.state.barClubLounge)
}

J'ai donc ces deux console.log(), les deux devraient être les mêmes. Je configure littéralement l'état pour qu'il soit le même que le event.target.checked Dans la ligne au-dessus!

Mais cela renvoie toujours le contraire de ce qu'il devrait.

Il en va de même lorsque j'utilise !this.state.barClubLounge; S'il commence faux, lors de mon premier clic, il reste faux, même si la case à cocher est cochée ou non est basée sur l'état !!

C'est un paradoxe fou et je n'ai aucune idée de ce qui se passe, aidez-moi!

40
Dan

La raison est setState est asynchrone , vous ne pouvez pas vous attendre à la valeur mise à jour state juste après la setState, si vous voulez vérifier la valeur, utilisez une méthode callback. Passez une méthode en tant que rappel qui sera exécutée une fois que le setState aura terminé sa tâche.

Pourquoi setState est asynchrone?

En effet, setState modifie le state et provoque un nouveau rendu. Cela peut être une opération coûteuse et la rendre synchronous peut laisser le navigateur ne pas répondre. Ainsi, les appels setState sont asynchronous ainsi que groupés pour une meilleure expérience et performances de l'interface utilisateur.

De Doc:

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

Utilisation de la méthode de rappel avec setState:

Pour vérifier la valeur state mise à jour juste après la setState, utilisez une méthode de rappel comme celle-ci:

setState({ key: value }, () => {
     console.log('updated state value', this.state.key)
})

Vérifie ça:

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

      this.state = {
         barClubLounge: false,
         seeTheTown: true,
         eventsEntertainment: true,
         familyFriendlyOnly: false
      }
   }

   handleOnChange = (event) => {  // Arrow function binds `this`
      let value = event.target.checked;

      if(event.target.className == "barClubLounge") {

         this.setState({ barClubLounge: value}, () => {  //here
             console.log(value);
             console.log(this.state.barClubLounge);
             //both will print same value
         });        

      }
   }

   render() {
      return (
          <input className="barClubLounge" type='checkbox' onChange={this.handleOnChange} checked={this.state.barClubLounge}/>
      )
   }
}

ReactDOM.render(<NightlifeTypes/>, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id='app'/>
47
Mayank Shukla

Puisque setState est une fonction asynchrone. Cela signifie qu'après avoir appelé la variable d'état setState ne change pas immédiatement. Donc, si vous souhaitez effectuer d'autres actions immédiatement après avoir changé l'état, vous devez utiliser la méthode de rappel de setstate dans votre fonction de mise à jour setState.

handleOnChange = (event) => { 
     let inputState = event.target.checked;
      if(event.target.className == "barClubLounge") {
         this.setState({ barClubLounge: inputState}, () => {  //here
             console.log(this.state.barClubLounge);
             //here you can call other functions which use this state 
             variable //
         });        
      }
   }
1
Asif J

Cela est dû à la conception en raison de considérations de performances. setState in React est une fonction garantie pour restituer Component, qui est un processus CPU coûteux. En tant que tel, ses concepteurs ont voulu optimiser en rassemblant plusieurs actions de rendu dans un, donc setState est asynchrone.

0
Nir O.