Quand utiliser le rappel de setState de React

191

Lorsqu'un état de composant de réaction change, la méthode de rendu est appelée. Par conséquent, pour tout changement d'état, une action peut être effectuée dans le corps des méthodes de rendu. Existe-t-il alors un cas d'utilisation particulier pour le rappel setState?

Sahil Jain
la source
4
Ce que vous demandez n'est actuellement pas clair. Pouvez-vous inclure du code?
Davin Tryon le
2
Le rappel setState est pour tout ce que vous voulez faire après que l'état a DEFINITELYbeen changé. Puisque setState est asynchrone, si vous voulez appeler un fx et être SÛR que le nouvel état est chargé, c'est à cela que sert le rappel
Jayce444
3
Le cas d'utilisation du rappel setState est assez clair. Vous l'utilisez lorsque vous souhaitez qu'une fonction s'exécute après la mise à jour d'un état SPECIFIC. Si vous mettez cette fonction à la render()place, elle s'exécutera à chaque fois que N'IMPORTE QUEL état est mis à jour, ce qui n'est probablement pas ce que vous voulez. Cela rendra également votre code moins lisible et logique.
M3RS

Réponses:

225

Oui il y en a, car setStateça marche d'une asynchronouscertaine manière. Cela signifie qu'après avoir appelé setStatelethis.state variable n'est pas immédiatement modifiée. donc si vous souhaitez effectuer une action immédiatement après avoir défini l'état sur une variable d'état et ensuite renvoyer un résultat, un rappel sera utile

Prenons l'exemple ci-dessous

....
changeTitle: function changeTitle (event) {
  this.setState({ title: event.target.value });
  this.validateTitle();
},
validateTitle: function validateTitle () {
  if (this.state.title.length === 0) {
    this.setState({ titleError: "Title can't be blank" });
  }
},
....

Le code ci-dessus peut ne pas fonctionner comme prévu car la titlevariable n'a peut-être pas muté avant que la validation ne soit effectuée. Vous vous demandez peut-être maintenant que nous pouvons effectuer la validation dans lerender() fonction elle-même, mais ce serait mieux et plus propre si nous pouvons gérer cela dans la fonction changeTitle elle-même, car cela rendrait votre code plus organisé et compréhensible

Dans ce cas, le rappel est utile

....
changeTitle: function changeTitle (event) {
  this.setState({ title: event.target.value }, function() {
    this.validateTitle();
  });

},
validateTitle: function validateTitle () {
  if (this.state.title.length === 0) {
    this.setState({ titleError: "Title can't be blank" });
  }
},
....

Un autre exemple sera quand vous voulez dispatchet agir lorsque l'état a changé. vous voudrez le faire dans un rappel et non pas render()comme il sera appelé à chaque fois qu'un nouveau rendu se produit et par conséquent, de nombreux scénarios de ce type sont possibles où vous aurez besoin d'un rappel.

Un autre cas est un API Call

Un cas peut survenir lorsque vous devez effectuer un appel d'API basé sur un changement d'état particulier, si vous faites cela dans la méthode de rendu, il sera appelé à chaque onStatechangement de rendu ou parce qu'un Prop transmis au Child Componentmodifié.

Dans ce cas, vous voudrez utiliser a setState callbackpour transmettre la valeur d'état mise à jour à l'appel d'API

....
changeTitle: function (event) {
  this.setState({ title: event.target.value }, () => this.APICallFunction());
},
APICallFunction: function () {
  // Call API with the updated value
}
....
Shubham Khatri
la source
3
Je comprends qu'il est de nature asynchrone. Ma question était de savoir s'il y avait quelque chose de spécifique que seul le rappel setState peut être utilisé pour cela, peut-être que le corps des méthodes de rendu peut ne pas prendre en charge (Quelque chose à part, disons une meilleure lisibilité du code.)
Sahil Jain
@SahilJain Validation est le bon exemple, vous ne voudrez pas le gérer dans la fonction render () car il sera alors appelé à chaque fois que vous apportez un changement dans le render () que vous voudrez l'appeler uniquement lorsque seule l'entrée change et donc dans la fonction elle
Shubham Khatri
React interdit de changer l'état pendant le rendu .. Donc son droit de mettre la validation dans le callback.
webdeb
if (this.title.length === 0) {devrait être this.state.title.length, non?
Dmitry Minkovsky
4
Le premier cas d'utilisation n'est probablement pas une bonne idée. Les rappels setState se déclenchent après le re-rendu, donc vous causez un double rendu sans raison valable. C'est exactement le but de l'argument de fonction (updater). Vous pouvez simplement exécuter setState(state => state.title.length ? { titleError: "Title can't be blank" } : null)et le changement s'empilera. Aucun double rend nécessaire.
R Esmond
47
this.setState({
    name:'value' 
},() => {
    console.log(this.state.name);
});
Araz Babayev
la source
14
Merci pour cet extrait de code, qui pourrait fournir une aide limitée et immédiate. Une explication appropriée améliorerait considérablement sa valeur à long terme en montrant pourquoi c'est une bonne solution au problème, et la rendrait plus utile aux futurs lecteurs avec d'autres questions similaires. Veuillez modifier votre réponse pour ajouter des explications, y compris les hypothèses que vous avez formulées.
Machavity
1
Lorsque vous souhaitez appeler une fonction après la modification de l'état, vous pouvez utiliser la méthode.
Araz Babayev
et si vous voulez définir plusieurs propriétés d'état comme le nom, le prénom, etc.?
Sumanth Varada
44

Le cas d'utilisation qui me vient à l'esprit est un apiappel, qui ne devrait pas entrer dans le rendu, car il fonctionnera pour eachun changement d'état. Et l'appel d'API ne doit être effectué que sur un changement d'état spécial, et non sur chaque rendu.

changeSearchParams = (params) => {
  this.setState({ params }, this.performSearch)
} 

performSearch = () => {
  API.search(this.state.params, (result) => {
    this.setState({ result })
  });
}

Par conséquent, pour tout changement d'état, une action peut être effectuée dans le corps des méthodes de rendu.

Très mauvaise pratique , car la renderméthode-doit être pure, cela signifie qu'aucune action, aucun changement d'état, aucun appel d'API ne doit être effectué, composez simplement votre vue et retournez-la. Les actions ne doivent être effectuées que sur certains événements. Render n'est pas un événement, mais componentDidMountpar exemple.

webdeb
la source
25

Envisagez l'appel setState

this.setState({ counter: this.state.counter + 1 })

IDÉE

setState peut être appelé dans la fonction asynchrone

Vous ne pouvez donc pas compter sur this. Si l'appel ci-dessus a été effectué dans une fonction asynchrone, il thisse référera à l'état du composant à ce moment-là, mais nous nous attendions à ce que cela fasse référence à la propriété à l'intérieur de l'état au moment de l'appel de setState ou du début de la tâche asynchrone. Et comme la tâche était un appel asynchrone, cette propriété peut avoir changé avec le temps. Ainsi, il n'est pas fiable d'utiliser un thismot-clé pour faire référence à une propriété d'état, nous utilisons donc une fonction de rappel dont les arguments sont previousState et props, ce qui signifie que lorsque la tâche asynchrone a été effectuée et qu'il était temps de mettre à jour l'état à l'aide de setState, l'appel prevState fera référence à l'état maintenant lorsque setState n'a pas encore commencé. Assurer la fiabilité que nextState ne serait pas corrompu.

Mauvais code: entraînerait une corruption des données

this.setState(
   {counter:this.state.counter+1}
 );

Code correct avec setState ayant une fonction de rappel:

 this.setState(
       (prevState,props)=>{
           return {counter:prevState.counter+1};
        }
    );

Ainsi, chaque fois que nous avons besoin de mettre à jour notre état actuel à l'état suivant en fonction de la valeur possédée par la propriété tout à l'heure et que tout cela se passe de manière asynchrone, il est bon d'utiliser setState comme fonction de rappel.

J'ai essayé de l'expliquer dans codepen ici CODE PEN

Aniket Jha
la source