Est-ce que React conserve la commande pour les mises à jour d’état?

Je sais que React peut effectuer des mises à jour d’état de manière asynchrone et par lots pour optimiser les performances. Par conséquent, vous ne pouvez jamais faire confiance à l’état mis à jour après avoir appelé setState . Mais pouvez-vous faire confiance à React pour mettre à jour l’état dans le même ordre que celui de setState

  1. le même composant?
  2. différents composants?

Pensez à cliquer sur le bouton dans les exemples suivants:

1. Y a-t-il une possibilité que a soit faux et que b soit vrai pour:

 class Container extends React.Component { constructor(props) { super(props); this.state = { a: false, b: false }; } render() { return 

2. Y a-t-il une possibilité que a soit faux et que b soit vrai pour:

 class SuperContainer extends React.Component { constructor(props) { super(props); this.state = { a: false }; } render() { return  } } class Container extends React.Component { constructor(props) { super(props); this.state = { b: false }; } render() { return 

Gardez à l’esprit que ce sont des simplifications extrêmes de mon cas d’utilisation. Je me rends compte que je peux le faire différemment, par exemple en mettant à jour les deux parameters d’état en même temps dans l’exemple 1 et en effectuant la deuxième mise à jour dans un rappel à la première mise à jour de l’exemple 2. et je ne m’intéresse qu’à la manière dont React effectue ces mises à jour d’état, rien d’autre.

Toute réponse soutenue par une documentation est grandement appréciée.

    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é

    • le même composant?

    Oui.

    • différents composants?

    Oui.

    L’ ordre des mises à jour est toujours respecté. Que vous voyiez ou non un état intermédiaire dépend de votre présence 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 mises en lots par défaut . Il existe une API instable pour forcer le traitement par lots en dehors des gestionnaires d’événements dans les cas rares où vous en avez besoin.

    Dans les futures versions (probablement React 17 et versions ultérieures), React mettra en lot 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 ceci est que peu importe le nombre d’ setState() de setState() dans le nombre de composants que vous faites dans un gestionnaire d’événements React , ils ne produiront qu’un seul re-render à la fin de l’événement . Ceci est crucial pour de bonnes performances dans les applications volumineuses, car si Child et Parent appellent chacun setState() lors de la gestion d’un événement click, vous ne souhaitez pas recréer deux fois Child .

    Dans les deux exemples, les setState() se produisent dans un gestionnaire d’événements React. Par conséquent, ils sont toujours regroupés à la fin de l’événement (et vous ne voyez pas l’état intermédiaire).

    Les mises à jour sont toujours fusionnées dans l’ordre où elles se produisent . Donc, si la première mise à jour est {a: 10} , la seconde est {b: 20} et la troisième est {a: 30} , l’état rendu sera {a: 30, b: 20} . La mise à jour plus récente de la même clé d’état (par exemple, comme dans mon exemple) “gagne” toujours.

    L’object this.state est mis à jour lorsque nous this.state l’interface utilisateur à la fin du lot. Donc, si vous avez besoin de mettre à jour un état en fonction d’un état antérieur (tel que l’incrémentation d’un compteur), vous devez utiliser la version fonctionnelle de setState(fn) qui vous donne l’état précédent, au lieu de lire this.state . Si vous êtes curieux de savoir pourquoi, je l’ai expliqué en détail dans ce commentaire .


    Dans votre exemple, nous ne verrions pas “l’état intermédiaire” car nous sums dans un gestionnaire d’événements React où le traitement par lots est activé (car React “sait” quand nous quittons cet événement).

    Cependant, à la fois dans React 16 et dans les versions antérieures, il n’y a pas encore de traitement par lot en dehors des gestionnaires d’événements React . Donc, si dans votre exemple nous avions un gestionnaire de réponses AJAX au lieu de handleClick , chaque setState() serait traité immédiatement, le cas setState() . Dans ce cas, oui, vous verriez 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 que ce comportement est différent selon que vous êtes 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 purger les modifications de manière synchrone). En attendant de changer le comportement par défaut (potentiellement dans React 17), vous pouvez utiliser une API pour forcer le traitement par lot :

     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 dans unstable_batchedUpdates c’est pourquoi ils sont mis en lots par défaut. Notez que l’encapsulation d’une mise à jour dans unstable_batchedUpdates deux fois n’a aucun effet. Les mises à jour sont vidées lorsque nous quittons l’appel unstable_batchedUpdates 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’à la Réaction 17 si vous devez forcer le traitement par lots dans certains cas en dehors des gestionnaires d’événements React.


    En résumé, il s’agit d’un sujet déroutant, car React ne traite que les lots à l’intérieur des gestionnaires d’événements par défaut. Cela changera dans les versions futures, et le comportement sera alors plus simple. Mais la solution n’est pas de réduire le nombre de lots , c’est de traiter davantage par défaut. C’est ce que nous allons faire.

    comme dans doc

    setState () met en queue les modifications de l’état du composant et indique à React que ce composant et ses enfants doivent être restitués avec l’état mis à jour. C’est la méthode principale que vous utilisez pour mettre à jour l’interface utilisateur en réponse aux gestionnaires d’événements et aux réponses du serveur.

    il va préformer le changement comme dans la queue ( FIFO : First In First Out) le premier appel sera le premier à préformer

    Plusieurs appels au cours du même cycle peuvent être regroupés. Par exemple, si vous essayez d’incrémenter une quantité d’article plus d’une fois dans le même cycle, cela se traduira par l’équivalent de:

     Object.assign( previousState, {quantity: state.quantity + 1}, {quantity: state.quantity + 1}, ... ) 

    https://reactjs.org/docs/react-component.html

    C’est en fait une question très intéressante mais la réponse ne devrait pas être trop compliquée. Il y a ce grand article sur le support qui répond à la question.

    1) Si vous faites cela

     this.setState({ a: true }); this.setState({ b: true }); 

    Je ne pense pas qu’il y aura une situation où a sera true et b sera false cause du traitement par lots .

    Cependant, si b est dépendant de a il pourrait bien y avoir une situation où vous ne pourriez pas obtenir l’état attendu.

     // assuming this.state = { value: 0 }; this.setState({ value: this.state.value + 1}); this.setState({ value: this.state.value + 1}); this.setState({ value: this.state.value + 1}); 

    Une fois tous les appels ci-dessus traités, this.state.value aura la valeur 1, et non 3, comme prévu.

    Ceci est mentionné dans l’article: setState accepts a function as its parameter

     // assuming this.state = { value: 0 }; this.setState((state) => ({ value: state.value + 1})); this.setState((state) => ({ value: state.value + 1})); this.setState((state) => ({ value: state.value + 1})); 

    Cela nous donnera this.state.value === 3