Scénario 1:
this.setState(({ foo }) => { ... });
Scénario 2:
const { foo } = this.state;
est foo garanti identique entre ceux-ci deux cas? Ou est-ce que setState s'exécutera de manière asynchrone et retournera une valeur différente en fonction d'autres setStates?
3 Réponses :
L'état peut être l'état lorsque vous accédez à l'état immédiatement après avoir utilisé this.setState , car this.setState est async .
Si vous avez besoin de calculer sur la base de l'état mis à jour, c'est-à-dire (après l'appel de this.state ), vous pouvez utiliser le 2ème argument pour la méthode qui est un rappel qui est déclenché après la validation des changements d'état .
this.setState(updateState, () => {
const { foo } = this.state;
console.log(foo); // updated foo
});
function updatedState({ foo }) {
// you can be sure that `foo`
// is from the previous state
// before setState is called
}
setState est asynchrone, et extraire les valeurs de l'état à utiliser dans setState est une source potentielle de bogues. setState peut accepter plusieurs arguments. Cela peut prendre juste un nouvel état, un rappel qui prend l'ancien état + les accessoires et retourne un nouvel état, un nouvel état et une fonction à exécuter après avoir défini un nouvel état, ou une combinaison. Exemple:
this.setState(
// function taking previous state + props,
// which should return updated state.
// this could also just be an object with
// the new state, if you don't need to rely
// on previous state.
(previousState, props) => {
if (previousState.something) {
return { something: somethingElse }
} else {
return { something: anotherThing }
}
}, () => {
// safe to use new state here,
// since state has been updated.
// but it's recommended to use
// componentDidUpdate instead!
})
Comme le mentionne React docs :
setState () ne met pas toujours immédiatement à jour le composant. Cela pourrait batch ou reporter la mise à jour à plus tard. Cela rend la lecture de this.state juste après avoir appelé setState () un piège potentiel. Au lieu de cela, utilisez componentDidUpdate ou un callback setState (setState (updater, callback)), dont le déclenchement est garanti après la mise à jour a été appliqué.
Nous pouvons donc utiliser le deuxième argument du setState pour passer un rappel où nous exécutons notre logique qui dépend de la mise à jour de la valeur de foo. Cependant, votre question initiale était de savoir si la valeur de foo dans const {foo} = this.state; et la valeur de foo dans this.setState (({foo}) => {.. .}); était le même.
Pour vérifier cela, nous pouvons comparer l'exécution d'un setState suivi de this.state.foo strong> et un setState suivi d'un autre setState (le second enregistrera simplement la valeur de foo au lieu de la muter). Veuillez vous référer à l'extrait suivant:
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script> <div id="root"></div>
class Example extends React.Component {
constructor() {
super();
this.state = {
foo: 0,
boo: 0
}
}
handleClickSetState = () => {
this.setState(({foo}) => ({foo: foo+1}));
this.setState(({foo}) => console.log("inside setState. foo: ", foo));
}
handleClickState = () => {
this.setState(({boo}) => ({boo: boo+1}));
console.log("outside setState. boo: ", this.state.boo)
}
render() {
return <React.Fragment>
<button onClick={this.handleClickState}>Test state</button>
<button onClick={this.handleClickSetState}>Test setState</button>
</React.Fragment>
}
}
ReactDOM.render(<Example />, document.getElementById("root"));
Comme nous pouvons le voir, le "cas d'état" est en retard de 1, ce à quoi on pourrait s'attendre puisque setState est asynchrone (et nous n'avons pas utilisé le deuxième argument de setState ). Cependant, le "cas setState" montre que la valeur correcte est toujours affichée, même si nous n'utilisons pas le second argument callback dans setState.
En conclusion const {foo} = this.state; vous donnera toujours la valeur immédiate de foo, indépendamment des fusions d'état en attente, tandis que this.setState (({foo}) => {...}); semble terminez d'abord les mises à jour en attente avant d'exécuter le rappel, ce qui signifie que foo aura toujours la valeur la plus récente.