Pourquoi n'y a-t-il pas de fonction asynchrone getState dans React?
La documentation nous dit que setState est asynchrone. Très bien, mais cela signifie que nous ne pouvons pas utiliser cet état.finement en toute sécurité et nous avons également besoin d'un getState asynchrone pour respecter l'ordre d'exécution.
D'après ce que j'ai compris, nous ne devrions jamais utiliser this.state et utiliser une fonction getState comme celle-ci:
getState(callback) {
this.setState((prevState) => {
callback(prevState) ;
});
}
...
this.getState((curState) => {
// we now can use the current state safely
}
Quelque chose me manque ici dans ma façon de penser? Pourquoi une telle fonction n'existe pas dans React?
-- MODIFIER --
Comme un de mes amis me l'a dit, ce n'était pas clair et, comme je ne suis pas convaincu, voici la première réponse, analysons un morceau de code:
simpleFunc() {
setState({ "counter" : 1 });
setState({ "counter" : 2 });
this.state.counter // => no garanty about the value
getState((curState) => { // ensure curState.counter is 2 });
}
Cet exemple simple montre que nous ne pouvons pas utiliser this.state directement dans toutes les situations puisque setState est asynchrone.
Voici un exemple de compteur dans lequel getState pourrait être utilisé: http://codepen.io/Epithor/pen/ZLavWR?editors=0010#0
Réponse courte: mauvaise pratique, même pas sûr que getState nous donne le courant
La solution de contournement est simple, mais le fait de pouvoir factoriser certaines fonctions et de les utiliser sans se soucier du contexte semble être intéressant, n'est-ce pas?
Ainsi, lorsque de nombreux événements se produisent dans un ordre particulier, certains événements modifient l’état, d’autres lisent l’état: comment en être sûr, lorsqu’un événement lit l’état avec this.state pour lire le bon état depuis tous ont changé sont async?
En fait, tout est une question de temps:
T : event 1, change state
T+1ms : event 2, change state
T+2ms : event 3, read state
T+3ms : event 4, change state
Comme vous ne pouvez pas prédire exactement quand se produira setState de l'événement 1 ou 2, comment pouvez-vous garantir que l'événement 3 lira réellement l'état défini à l'événement 2?
Réponse courte: Les événements sont mis en file d'attente dans la pile JS, tandis que les changements d'état sont mis en file d'attente dans la file d'attente React interne. La file d'attente React interne est complètement désempilée avant de donner la main.
Ce n’est en fait pas un bug/problème, mais une décision d’architecture: la state
n’est pas destinée à être utilisée comme une simple propriété/variable/stockage, elle est spécifiquement destinée à être utilisée pour une interface/un état visuel et, en tant que telle, n’a être mis à jour à chaque appel. Il utilise une file d'attente interne. Par conséquent, si vous permutez plusieurs fois l'état avant le rendu, il ne le mettra à jour qu'une fois avec la valeur finale. Lorsque la méthode render
sera invoquée, il contiendra la bonne valeur.
Si vous avez simplement besoin de stocker/récupérer des informations pendant l'exécution ou entre des méthodes s'exécutant dans la même phase (componentWillReceiveProps
et shouldComponentUpdate
, par exemple), vous pouvez utiliser this.anyProperty
en toute sécurité, comme toujours:
componentWillReceiveProps() {
this.value = 'guaranteed';
return true;
}
shouldComponentUpdate() {
if (this.value === 'guaranteed') {
console.log('will always return true');
}
}
componentDidUpdate() {
this.value = ''; //cleanup
}
Dans l'exemple ci-dessus, si vous utilisiez "setState", rien ne garantirait que la valeur serait toujours mise à jour dans "shouldComponentUpdate", mais cela ne devrait pas avoir d'importance si vous l'utilisez aux fins pour lesquelles il a été conçu. Les changements d’état sont garantis d’avoir été vidés au plus tard le temps render
; il ne doit donc contenir que des informations utilisées dans la phase de rendu, et non des données transactionnelles/internes pour vos objets. Vous êtes libre de continuer à utiliser les propriétés d'objet comme d'habitude.
setState est asynchrone, vous ne pouvez donc pas accéder immédiatement à la propriété que vous avez modifiée. CEPENDANT, vous pouvez effectuer une action après avoir modifié l'état. Dans ce cas, vous pouvez effectuer les actions suivantes:
...
this.state = {
x = 1
}
...
this.setState({
x = 2
}, () => {
console.log(this.state.x) // outputs 2
});
la fonction setState est appelée sur un tick en file d'attente, vous pouvez donc mettre x nombre de setStates en file d'attente, ils seront tous exécutés au prochain tick.