43 votes

Pourquoi Async Await fonctionne-t-il avec React setState?

J'ai été en utilisant async attendent avec babel dans mon ReactJS projet. J'ai découvert un moyen pratique d'utilisation avec Réagissent setState que je voudrais juste mieux comprendre. Considérer ce code:

handleChange = (e) => {
  this.setState({[e.target.name]: e.target.value})
  console.log('synchronous code')
}

changeAndValidate = async (e) => {
  await this.handleChange(e)
  console.log('asynchronous validation code')
}

componentDidUpdate() {
  console.log('updated component')    
}

Mon intention est de l'asynchrone de validation de code à exécuter après que le composant est mis à jour. Et ça marche!!! L'résultant du journal de la console affiche:

synchronous code
updated component
asynchronous validation code

Le code de validation sera exécuté uniquement après handleChange a mis à jour l'état et le nouvel état est rendu.

Généralement d'exécuter du code après l'etat a mis à jour, vous devez utiliser un callback après ce.setState. Ce qui signifie que si vous voulez exécuter quoi que ce soit après handleChange, vous devez donner un rappel paramètre qui est ensuite transmis à setState. Pas assez. Mais dans l'exemple de code, en quelque sorte attendent sait que handleChange est terminée après que l'état a mis à jour... Mais je pensais attendre fonctionne uniquement avec des promesses et attend une promesse à résoudre avant de continuer. Theres aucune promesse et aucune résolution handleChange... Comment sait-elle que d'attendre??

L'implication semble être que setState est exécuté de manière asynchrone et attendent est en quelque sorte au courant de quand il se termine. Peut-être setState utilise des promesses à l'interne?

Versions:

réagir: "^15.4.2"

babel-core: "^6.26.0"

babel-preset-env: "^1.6.0",

babel-preset-réagir: "^6.24.1",

babel-preset-stade 0: "^6.24.1"

babel-plugin-système-import-transformateur: "^3.1.0",

babel-plugin-transformer-décorateurs-héritage: "^1.3.4",

babel-plugin-transformer-runtime: "^6.23.0"

51voto

linasmnew Points 2079

J'ai essayé de faire de mon mieux afin de simplifier et de compléter Davin, de répondre, de sorte que vous pouvez obtenir une meilleure idée de ce qui se passe réellement ici:


  1. attendent est placé en face de ce.handleChange, cela permettra de planifier l'exécution du reste de changeAndValidate fonction à exécuter uniquement lorsque attendent résout la valeur spécifiée pour la droite, dans ce cas, la valeur retournée par cette.handleChange
  2. c'.handleChange, sur le droit de l' attendre, exécute:

    2.1. setState exécute son programme de mise à jour, mais parce que setState ne garantit pas la mise à jour immédiate de potentiellement les horaires de la mise à jour pour arriver à un moment plus tard (il n'a pas d'importance si c'est immédiat ou plus tard dans le temps, tout ce qui importe, c'est que c'est prévu)

    2.2. console.log ("code synchrone') fonctionne...

    2.3. c'.handleChange sort alors de retour indéfini (renvoie undefined parce que les fonctions de retour indéfini sauf indication contraire)

  3. attendent alors prend ce pas défini et que ce n'est pas une promesse, il la convertit en résolu promesse, à l'aide de la Promesse.résoudre(undefined) et attend qu'il - elle n'est pas immédiatement disponible car derrière les coulisses, il est transmis à ses .ensuite , une méthode asynchrone:

"Rappels passé dans une promesse qui ne sera jamais appelé avant l' l'achèvement de l'exécution de la boucle d'événement JavaScript"

3.1. cela signifie que indéfini seront placés à l'arrière de la file d'attente d'événements, (ce qui signifie qu'il est désormais derrière notre setState programme de mise à jour dans la file d'attente d'événements...)

  1. boucle d'événement arrive et ramasse notre setState mise à jour, qui s'exécute maintenant...

  2. boucle d'événement atteint et ramasse pas défini, qui renvoie undefined (nous pourrions stocker ce si nous le voulions, d'où l' = couramment utilisé en face de vous attendent pour stocker l'résolu suite)

    5.1. Promesse.resolve() est maintenant terminé, ce qui signifie attendre n'est plus dans l'affect, de sorte que le reste de la fonction peut reprendre

  3. votre validation de code s'exécute

5voto

Davin Tryon Points 16838

Je n'ai pas testé encore, mais voici ce que je pense qui se passe:

L' undefined retournée par await est mis en file d'attente après l' setState de rappel. L' await fait Promise.resolve - dessous (en regenerator-runtime) qui à son tour donne le contrôle à l'élément suivant de la boucle d'événements.

Donc, est-ce une coïncidence que l' setState de rappel qui arrive à être mis en file d'attente à l'avance de l' await.

Vous pouvez le tester en mettant un setTimeout(f => f, 0) autour de l' setState.

regenerator-runtime en babel est essentiellement une boucle qui utilise Promise.resolve pour le contrôle du rendement. Vous pouvez voir l'intérieur de la _asyncToGenerator, il a un Promise.resolve.

4voto

Gabriel Bleu Points 3956

setState() n'est pas toujours immédiatement mettre à jour le composant doc

Mais il est peut-être le cas ici.

Si vous souhaitez remplacer le rappel avec une promesse que vous pouvez appliquer vous-même :

setStateAsync(state) {
  return new Promise((resolve) => {
    this.setState(state, resolve)
  });
}

handleChange = (e) => {
  return this.setStateAsync({[e.target.name]: e.target.value})
}

ref : https://medium.com/front-end-hacking/async-await-with-react-lifecycle-methods-802e7760d802

1voto

Sterling Archer Points 8480

Le rv ou la valeur de retour d'attente est défini comme:

 rv
Returns the fulfilled value of the promise, or the value itself if it's not a Promise.
 

Donc, puisque handleChange n'est pas une valeur asynchrone ou promise, il renvoie simplement la valeur naturelle (dans ce cas, il n'y a pas de retour, donc undefined ). Ainsi, il n'y a pas de déclencheur de boucle d'événement asynchrone ici pour "lui faire savoir que handleChange est fait", il s'exécute simplement dans l'ordre que vous lui avez donné.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X