Je travaille sur React.
TLDR:
Mais pouvez-vous faire confiance à React pour mettre à jour l'état dans le même ordre que setState est appelé
Oui.
Oui.
L' ordre des mises à jour est toujours respecté. Que vous voyiez un état intermédiaire "entre" eux ou non dépend de si vous êtes dans un lot ou non.
Actuellement (React 16 et versions antérieures), seules les mises à jour à l'intérieur des gestionnaires d'événements React sont regroupées par défaut . Il existe une API instable pour forcer le traitement par lots en dehors des gestionnaires d'événements dans de rares cas où vous en avez besoin.
Dans les versions futures (probablement React 17 et versions ultérieures), React regroupera toutes les mises à jour par défaut afin que vous n'ayez pas à y penser. Comme toujours, nous annoncerons tout changement à ce sujet sur le blog React et dans les notes de publication.
La clé pour comprendre cela est que quel que soit le nombre d' setState()
appels dans le nombre de composants que vous effectuez dans un gestionnaire d'événements React , ils ne produiront qu'un seul rendu à la fin de l'événement . Ceci est crucial pour de bonnes performances dans les applications volumineuses, car si Child
et à Parent
chaque appel setState()
lors de la gestion d'un événement de clic, vous ne souhaitez pas effectuer le rendu Child
deux fois.
Dans vos deux exemples, les setState()
appels se produisent dans un gestionnaire d'événements React. Par conséquent, ils sont toujours vidés ensemble à la fin de l'événement (et vous ne voyez pas l'état intermédiaire).
Les mises à jour sont toujours fusionnées de manière superficielle dans l'ordre dans lequel elles se produisent . Donc, si la première mise à jour est {a: 10}
, la deuxième est {b: 20}
et la troisième est {a: 30}
, l'état rendu sera {a: 30, b: 20}
. La mise à jour la plus récente de la même clé d'état (par exemple, comme a
dans mon exemple) "gagne" toujours.
L' this.state
objet est mis à jour lorsque nous rendons à nouveau l'interface utilisateur à la fin du lot. Donc, si vous avez besoin de mettre à jour l'état en fonction d'un état précédent (tel que l'incrémentation d'un compteur), vous devez utiliser la setState(fn)
version fonctionnelle qui vous donne l'état précédent, au lieu de lire à partir de this.state
. Si vous êtes curieux de connaître le raisonnement, je l'ai expliqué en détail dans ce commentaire .
Dans votre exemple, nous ne verrons pas "l'état intermédiaire" car nous sommes dans un gestionnaire d'événements React où le traitement par lots est activé (car React "sait" quand nous quittons cet événement).
Cependant, tant dans React 16 que dans les versions antérieures, il n'y a pas encore de traitement par lots par défaut en dehors des gestionnaires d'événements React . Donc, si dans votre exemple nous avions un gestionnaire de réponse AJAX à la place de handleClick
, chacun setState()
serait traité immédiatement comme il se produit. Dans ce cas, oui, vous voulez voir un état intermédiaire:
promise.then(() => {
// We're not in an event handler, so these are flushed separately.
this.setState({a: true}); // Re-renders with {a: true, b: false }
this.setState({b: true}); // Re-renders with {a: true, b: true }
this.props.setParentState(); // Re-renders the parent
});
Nous nous rendons compte qu'il est peu pratique que le comportement soit différent selon que vous soyez dans un gestionnaire d'événements ou non . Cela changera dans une future version de React qui regroupera toutes les mises à jour par défaut (et fournira une API opt-in pour effacer les modifications de manière synchrone). Jusqu'à ce que nous changions le comportement par défaut (potentiellement dans React 17), il existe une API que vous pouvez utiliser pour forcer le traitement par lots :
promise.then(() => {
// Forces batching
ReactDOM.unstable_batchedUpdates(() => {
this.setState({a: true}); // Doesn't re-render yet
this.setState({b: true}); // Doesn't re-render yet
this.props.setParentState(); // Doesn't re-render yet
});
// When we exit unstable_batchedUpdates, re-renders once
});
Les gestionnaires d'événements React en interne sont tous encapsulés, unstable_batchedUpdates
c'est pourquoi ils sont regroupés par défaut. Notez que l'encapsulation d'une mise à jour unstable_batchedUpdates
deux fois n'a aucun effet. Les mises à jour sont vidées lorsque nous quittons l' unstable_batchedUpdates
appel le plus externe .
Cette API est "instable" dans le sens où nous la supprimerons lorsque le traitement par lots est déjà activé par défaut. Cependant, nous ne le supprimerons pas dans une version mineure, vous pouvez donc vous y fier en toute sécurité jusqu'à React 17 si vous devez forcer le traitement par lots dans certains cas en dehors des gestionnaires d'événements React.
Pour résumer, c'est un sujet déroutant car React ne fait par défaut que des lots à l'intérieur des gestionnaires d'événements. Cela changera dans les versions futures, et le comportement sera alors plus simple. Mais la solution n'est pas de mettre moins de lots en lots , c'est d'en lots plus par défaut. C'est ce que nous allons faire.