React setState ne pas mettre à jour immédiatement

je travaille sur une application todo. C'est une version très simplifiée du code fautif. J'ai une case à cocher:

 <p><input type="checkbox"  name="area" checked={this.state.Pencil}   onChange={this.checkPencil}/> Writing Item </p>

Voici la fonction qui appelle la case:

checkPencil(){
   this.setState({
      pencil:!this.state.pencil,
  }); 
  this.props.updateItem(this.state);
}

updateItem est une fonction qui est mappée à dispatch to redux

function mapDispatchToProps(dispatch){
  return bindActionCreators({ updateItem}, dispatch);
}

mon problème est que lorsque j'appelle l'action updateItem et la console.journal de l'état, il est toujours de 1 pas en arrière. Si la case n'est pas cochée et pas vrai, j'ai toujours l'état de l'être vrai passé à la fonction updateItem. Dois-je appeler une autre fonction pour forcer l'état de mise à jour?

36
demandé sur lost9123193 2016-07-25 03:27:19

8 réponses

vous devriez invoquer votre seconde fonction comme un callback de setState, comme setsate se produit asynchrone. Quelque chose comme:

this.setState({pencil:!this.state.pencil}, myFunction)

cependant dans votre cas, puisque vous voulez que cette fonction soit appelée avec un paramètre, vous allez devoir être un peu plus créatif, et peut-être créer votre propre fonction qui appelle la fonction dans les accessoires:

myFunction = () => {
  this.props.updateItem(this.state)
}

combinez ceux-ci ensemble et cela devrait fonctionner.

62
répondu Ben Hare 2016-07-25 00:49:22

appel setState() in React est asynchrone, pour diverses raisons (principalement la performance). Sous les couvertures Réagir lot de multiples appels à setState() dans une mutation à un seul État, puis restituer le composant une seule fois, plutôt que de le restituer pour chaque changement d'état.

heureusement, la solution est assez simple - setState accepte un paramètre de rappel:

checkPencil(){
   this.setState({
      pencil:!this.state.pencil,
  }, function () {
      this.props.updateItem(this.state);
  }.bind(this));
}
12
répondu rossipedia 2016-07-25 00:56:32

lorsque vous mettez à jour votre état en utilisant une propriété de l'état actuel, la documentation React vous conseille d'utiliser la fonction Appel version de setState au lieu de l'objet.

setState((state, props) => {...}) au lieu de setState(object).

La raison en est que setState est plus une requête pour que l'état change qu'un changement immédiat. Réagir lots ceux setState appels à l'amélioration de la performance.

ce qui signifie que la propriété de l'état que vous vérifiez pourrait ne pas être stable. C'est un écueil potentiel d'être conscient de.

Pour plus d'informations, voir la documentation ici: https://facebook.github.io/react/docs/react-component.html#setstate


pour répondre À votre question, je le ferais.

checkPencil(){
    this.setState((prevState) => {
        return {
            pencil: !prevState.pencil
        };
    }, () => {
        this.props.updateItem(this.state)
    });
}
8
répondu GBL 2017-06-07 20:05:19

C'est parce que ça arrive de façon asynchrone, signifie donc que dans ce temps pourrait ne pas être mis à jour encore...

selon la documentation React v. 16, Vous devez utiliser une deuxième forme de setState() qui accepte une fonction plutôt qu'un objet:

Les Mises À Jour Des États Peuvent Être Asynchrones

peut Réagir par lots de plusieurs setState() appels en une seule mise à jour pour performance.

parce que ça.des accessoires et de la ce.l'état peut être mis à jour en mode asynchrone, vous ne devrait pas compter sur leurs valeurs pour calculer l'état suivant.

Par exemple, ce code peut ne pas mettre à jour le compteur:

// Wrong
this.setState({
  counter: this.state.counter + this.props.increment,
});

pour le corriger, utilisez une seconde forme de setState () qui accepte une fonction plutôt que d'un objet. Cette fonction recevra l'état précédent comme premier argument, et les accessoires au moment de la mise à jour est appliquée comme deuxième argument:

// Correct
this.setState((prevState, props) => ({
  counter: prevState.counter + props.increment
}));
6
répondu Alireza 2017-10-18 12:08:11

j'ai utilisé les suggestions de rossipedia et de Ben Hare et j'ai fait ce qui suit:

checkPencil(){
   this.setState({
      pencil:!this.state.pencil,
   }, this.updatingItem); 
}

updatingItem(){
    this.props.updateItem(this.state)
}
2
répondu lost9123193 2016-07-25 01:34:13

Ben a une excellente réponse pour la façon de résoudre le problème immédiat, mais je conseillerais aussi d'éviter de dupliquer l'état

si un État est dans redux, votre case à cocher devrait lire son propre état à partir d'un accessoire ou d'un magasin au lieu de garder une trace de l'état de vérification dans son propre composant et dans le magasin global

Faire quelque chose comme ceci:

<p>
    <input
        type="checkbox"
        name="area" checked={this.props.isChecked}
        onChange={this.props.onChange}
    />
    Writing Item
</p>

La règle générale est que si vous trouvez qu'un État est nécessaire à plusieurs endroits, hissez-le à un parent (pas toujours redux) afin de maintenir l'avoir une seule source de vérité

2
répondu CheapSteaks 2017-04-13 14:05:14

essayez ceci

this.setState({inputvalue: e.target.value}, function () {
    console.log(this.state.inputvalue);
    this.showInputError(inputs[0].name);
}); 

fonction showInputError pour validation si vous utilisez des formulaires

2
répondu Anish 2017-08-09 12:27:00

d'abord définir votre valeur. après procéder vos travaux.

this.setState({inputvalue: e.target.value}, function () {
    this._handleSubmit();
}); 

_handleSubmit() {
   console.log(this.state.inputvalue);
   //Do your action
}
0
répondu Kumaresan 2018-02-23 15:13:17