Je sais que React peut effectuer des mises à jour d'état de manière asynchrone et par lots pour l'optimisation des performances. Par conséquent, vous ne pouvez jamais faire confiance à l'état à mettre à jour après avoir appelé setState
. Mais pouvez - vous faire confiance Réagir à mettre à jour l'état dans le même ordre que l' setState
on appelle pour
- le même composant?
- différents composants?
Pensez à cliquer sur le bouton dans les exemples suivants:
1. Y a-t-il jamais une possibilité que a soit faux et b soit vrai pour:
class Container extends React.Component {
constructor(props) {
super(props);
this.state = { a: false, b: false };
}
render() {
return <Button onClick={this.handleClick}/>
}
handleClick = () => {
this.setState({ a: true });
this.setState({ b: true });
}
}
2. Y a-t-il jamais une possibilité que a soit faux et b soit vrai pour:
class SuperContainer extends React.Component {
constructor(props) {
super(props);
this.state = { a: false };
}
render() {
return <Container setParentState={this.setState.bind(this)}/>
}
}
class Container extends React.Component {
constructor(props) {
super(props);
this.state = { b: false };
}
render() {
return <Button onClick={this.handleClick}/>
}
handleClick = () => {
this.props.setParentState({ a: true });
this.setState({ b: true });
}
}
Gardez à l'esprit que ce sont des simplifications extrêmes de mon cas d'utilisation. Je me rends compte que je peux faire cela différemment, par exemple mettre à jour les deux paramètres d'état en même temps dans l'exemple 1, ainsi qu'exécuter la deuxième mise à jour d'état dans un rappel de la première mise à jour d'état dans l'exemple 2. Cependant, ce n'est pas ma question, et je ne suis intéressé que s'il existe une manière bien définie dont React effectue ces mises à jour d'état, rien d'autre.
Toute réponse appuyée par de la documentation est grandement appréciée.
la source
Réponses:
Je travaille sur React.
TLDR:
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 siChild
et àParent
chaque appelsetState()
lors de la gestion d'un événement de clic, vous ne souhaitez pas effectuer le renduChild
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, commea
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 lasetState(fn)
version fonctionnelle qui vous donne l'état précédent, au lieu de lire à partir dethis.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
, chacunsetState()
serait traité immédiatement comme il se produit. Dans ce cas, oui, vous voulez voir un état intermédiaire: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 :
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 à jourunstable_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.
la source
obj.a = true; obj.b = true
) et ensuite de fairethis.setState(obj)
. Ceci est sûr, que vous soyez ou non dans un gestionnaire d'événements. Cela pourrait être une bonne astuce si vous vous retrouvez souvent à faire l'erreur de définir l'état plusieurs fois en dehors des gestionnaires d'événements.componentDidUpdate
et d'autres rappels de cycle de vie à partir de React 16? Merci d'avance!C'est en fait une question assez intéressante mais la réponse ne devrait pas être trop compliquée. Il y a cet excellent article sur le médium qui a une réponse.
1) Si vous faites cela
Je ne pense pas qu'il y aura une situation où
a
seratrue
etb
sera àfalse
cause du traitement par lots .Cependant, si
b
dépend de,a
il peut effectivement y avoir une situation où vous n'obtiendrez pas l'état attendu.Une fois que tous les appels ci-dessus sont traités, il y
this.state.value
aura 1, pas 3 comme vous vous attendez.Ceci est mentionné dans l'article:
setState accepts a function as its parameter
Cela nous donnera
this.state.value === 3
la source
this.state.value
est mis à jour à la fois dans les gestionnaires d'événements (oùsetState
est groupé) et les rappels AJAX (oùsetState
n'est pas groupé). Dans les gestionnaires d'événements, j'utiliserais leupdater function
pour toujours être sûr de mettre à jour l'état en utilisant l'état actuellement mis à jour fourni par la fonction. Dois-je utilisersetState
avec une fonction de mise à jour dans le code du rappel AJAX même si je sais qu'il n'est pas groupé? Pourriez-vous s'il vous plaît clarifier l'utilisation desetState
dans un rappel AJAX avec ou sans utiliser une fonction de mise à jour? Je vous remercie!setState
seraient exécutés mais le dernier gagnerait.Plusieurs appels au cours du même cycle peuvent être groupés ensemble. 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:
https://reactjs.org/docs/react-component.html
la source
comme dans doc
il préformera le changement comme dans la file d'attente ( FIFO : First In First Out) le premier appel sera le premier à effectuer
la source