React setState ne met pas à jour l'état


91

Donc j'ai ceci:

let total = newDealersDeckTotal.reduce(function(a, b) {
  return a + b;
},
0);

console.log(total, 'tittal'); //outputs correct total
setTimeout(() => {
  this.setState({dealersOverallTotal: total});
}, 10);

console.log(this.state.dealersOverallTotal, 'dealersOverallTotal1'); //outputs incorrect total

newDealersDeckTotal est juste un tableau de nombres, [1, 5, 9]par exemple this.state.dealersOverallTotalne donne pas le total correct mais le totalfait? J'ai même mis un délai d'attente pour voir si cela résolvait le problème. toute évidence ou devrais-je poster plus de code?



@Assan applaudit !!
Le ver

Outre ce qui est dit dans les réponses, vous enregistrez explicitement la valeur de l'état, avant d'appeler setState.
Felix Kling

1
@FelixKling non, j'appelle this.state après l' avoir défini. J'enregistre une variable avant. non?
Le ver

En raison du délai d'expiration, votre setStateest effectivement exécuté une fois que vous avez enregistré l'état. Je pense que ce que vous vouliez faire lors du débogage était de placer la console.logpièce à l'intérieur du délai d'expiration et à l' setStateextérieur.
Fabian Schultz

Réponses:


181

setState()est généralement asynchrone, ce qui signifie qu'au moment où vous console.logl'état, il n'est pas encore mis à jour. Essayez de mettre le journal dans le rappel de la setState()méthode. Il est exécuté une fois le changement d'état terminé:

this.setState({ dealersOverallTotal: total }, () => {
  console.log(this.state.dealersOverallTotal, 'dealersOverallTotal1');
}); 

1
En plus de cela, l'OP enregistre explicitement la valeur de l'état avant l' appel setState.
Felix Kling

Cela fonctionne aussi pour moi, dans le passé, j'ai utilisé ceci: `this.setState ({someVar: newValue}, function () {console.log (" forcer la mise à jour}); 'mais pour une raison quelconque, ce n'était pas inquiétant plus, quand j'ai mis à jour le code comme décrit ci-dessus, cela fonctionne. Une idée pourquoi?
Jozcar

@Jozcar Devrait fonctionner aussi, la syntaxe n'était pas correcte (parenthèses manquantes):this.setState({someVar: newValue},function(){ console.log("force update") });
Fabian Schultz

imgur.com/Ku0OjTl Veuillez me dire ce que je dois faire pour me débarrasser de ce problème.
Johncy

Cela ne fonctionne pas si vous utilisez un useStatehook dans un composant fonctionnel. Utilisez useEffectplutôt pour un effet après le rendu.
Hasan Sefa Ozalp le

16

setState est asynchrone. Vous pouvez utiliser la méthode de rappel pour obtenir l'état mis à jour.

changeHandler(event) {
    this.setState({ yourName: event.target.value }, () => 
    console.log(this.state.yourName));
 }

10

Utiliser async / await

async changeHandler(event) {
    await this.setState({ yourName: event.target.value });
    console.log(this.state.yourName);
}

Je fais la même chose. A travaillé pour moi
prodeveloper

8

L' setState()opération est asynchrone et par conséquent, votre console.log()sera exécuté avant que setState()les valeurs ne mute et que vous voyez donc le résultat.

Pour le résoudre, enregistrez la valeur dans la fonction de rappel de setState(), comme:

setTimeout(() => {
    this.setState({dealersOverallTotal: total},
    function(){
       console.log(this.state.dealersOverallTotal, 'dealersOverallTotal1');
    });
}, 10)

JavaScript est toujours synchrone.
Santosh Singh

1
@santoshsingh vous avez une idée fausse. Les appels d'API, les délais d'expiration se produisent tous de manière asynchrone.
Shubham Khatri

Comme vous l'avez mentionné ci-dessus, javascript est asynchrone - ce n'est pas correct. C'est principalement synchrone et pour les cas, c'est asynchrone. stackoverflow.com/questions/2035645/…
Santosh Singh

@santoshsingh. Ohh c'était une erreur de ma part. N'a pas formé la phrase correctement
Shubham Khatri

utilisation très intelligente du callback pour s'assurer que l'état est mis à jour avant l'appel suivant!
user1204214

5

En cas de crochets, vous devez utiliser un useEffectcrochet.

const [fruit, setFruit] = useState('');

setFruit('Apple');

useEffect(() => {
  console.log('Fruit', fruit);
}, [fruit])

Génial, cela fonctionne avec useEffect. Mais pourquoi en a-t-il besoin?
alex351 le

useEffects'exécute à chaque re-rendu, et si les éléments passés dans le tableau sont des variables d'état, sable changé. Ainsi, lorsque le fruit a changé et que le composant est à nouveau rendu, cet useEffect s'exécute.
Siraj Alam le

Je lance setFruit et console.log fruit en dehors de useEffect, et cela ne change pas. : /
alex351

3

Le setstate est asynchrone dans react, donc pour voir l'état mis à jour dans la console, utilisez le rappel comme indiqué ci-dessous (la fonction de rappel s'exécutera après la mise à jour de setstate)

entrez la description de l'image ici

La méthode ci-dessous n'est "pas recommandée" mais pour comprendre, si vous changez directement l'état, vous pouvez voir l'état mis à jour dans la ligne suivante. Je répète que ce n'est "pas recommandé"

entrez la description de l'image ici


MERCI ça y est, vous devez définir directement la variable
notacorn le


0

J'ai eu un problème lors de la définition de l'état de réaction plusieurs fois (il a toujours utilisé l'état par défaut). Suite à ce problème de réaction / github a fonctionné pour moi

const [state, setState] = useState({
  foo: "abc",
  bar: 123
});

// Do this!
setState(prevState => {
  return {
    ...prevState,
    foo: "def"
  };
});
setState(prevState => {
  return {
    ...prevState,
    bar: 456
  };
});

0

J'ai eu la même situation avec un code alambiqué, et rien des suggestions existantes n'a fonctionné pour moi.

Mon problème était que cela setStatese produisait à partir de la fonction de rappel, émise par l'un des composants. Et mon soupçon est que l'appel se produisait de manière synchrone, ce qui a empêché setStatedu tout de définir l'état.

En termes simples, j'ai quelque chose comme ça:

render() {
    <Control
        ref={_ => this.control = _}
        onChange={this.handleChange}
        onUpdated={this.handleUpdate} />
}

handleChange() {
    this.control.doUpdate();
}

handleUpdate() {
    this.setState({...});
}

La façon dont je devais "réparer" c'était de mettre doUpdate()en setTimeoutcomme ceci:

handleChange() {
    setTimeout(() => { this.control.doUpdate(); }, 10);
}

Pas idéal, mais sinon ce serait une refactorisation importante.

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.