Wann wird der Rückruf von React setState verwendet?


191

Wenn sich der Status einer Reaktionskomponente ändert, wird die Rendermethode aufgerufen. Daher kann für jede Statusänderung eine Aktion im Render-Methodenkörper ausgeführt werden. Gibt es dann einen bestimmten Anwendungsfall für den setState-Rückruf?


4
Es ist derzeit unklar, was Sie fragen. Können Sie Code einfügen?
Davin Tryon

2
Der setState-Rückruf gilt für alles, was Sie tun möchten, nachdem der Status DEFINITELY geändert wurde. Da setState asynchron ist, ist der Rückruf genau dafür vorgesehen, wenn Sie einen FX aufrufen und sicher sein möchten, dass der neue Status geladen ist
Jayce444,

3
Der Anwendungsfall für den setState-Rückruf ist ziemlich klar. Sie verwenden es, wenn eine Funktion ausgeführt werden soll, nachdem ein SPEZIFISCHER Status aktualisiert wurde. Wenn Sie diese Funktion render()stattdessen aktivieren, wird sie jedes Mal ausgeführt, wenn ein Status aktualisiert wird. Dies ist wahrscheinlich nicht das, was Sie möchten. Dadurch wird Ihr Code auch weniger lesbar und logisch.
M3RS

Antworten:


222

Ja gibt es, da setStatefunktioniert in gewisser asynchronousWeise. Das heißt, nach dem Aufruf wird setStatedie this.stateVariable nicht sofort geändert. Wenn Sie also unmittelbar nach dem Festlegen des Status für eine Statusvariable eine Aktion ausführen und dann ein Ergebnis zurückgeben möchten, ist ein Rückruf hilfreich

Betrachten Sie das folgende Beispiel

....
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" });
  }
},
....

Der obige Code funktioniert möglicherweise nicht wie erwartet, da die titleVariable möglicherweise nicht mutiert ist, bevor die Validierung durchgeführt wird. Jetzt fragen Sie sich vielleicht, ob wir die Validierung in der render()Funktion selbst durchführen können, aber es wäre besser und sauberer, wenn wir dies in der changeTitle-Funktion selbst handhaben könnten, da dies Ihren Code organisierter und verständlicher machen würde

In diesem Fall ist ein Rückruf hilfreich

....
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" });
  }
},
....

Ein weiteres Beispiel ist, wann Sie möchten dispatchund wann sich der Status ändert. Sie möchten dies in einem Rückruf tun und nicht so, render()wie es bei jedem erneuten Rendern genannt wird. Daher sind viele solcher Szenarien möglich, in denen Sie einen Rückruf benötigen.

Ein anderer Fall ist a API Call

Ein Fall kann auftreten, wenn Sie einen API-Aufruf basierend auf einer bestimmten Statusänderung ausführen müssen. Wenn Sie dies in der Render-Methode tun, wird dieser bei jeder Render- onStateÄnderung aufgerufen oder weil ein Prop an die Child ComponentÄnderung weitergegeben wurde.

In diesem Fall möchten Sie a verwenden setState callback, um den aktualisierten Statuswert an den API-Aufruf zu übergeben

....
changeTitle: function (event) {
  this.setState({ title: event.target.value }, () => this.APICallFunction());
},
APICallFunction: function () {
  // Call API with the updated value
}
....

3
Ich verstehe, dass es asynchroner Natur ist. Meine Frage war, ob es etwas Bestimmtes gibt, für das nur der setState-Rückruf verwendet werden kann, den der Render-Methodenkörper möglicherweise nicht unterstützt (etwas anderes als eine bessere Lesbarkeit des Codes).
Sahil Jain

@SahilJain Validation ist das richtige Beispiel. Sie möchten es nicht in der Funktion render () behandeln, da es dann jedes Mal aufgerufen wird, wenn Sie Änderungen an render () vornehmen. Sie möchten es nur aufrufen, wenn sich nur die Eingabe ändert und daher in der Funktion selbst
Shubham Khatri

React verbietet es, den Status während des Renderns zu ändern. Es ist also das Recht, die Validierung in den Rückruf aufzunehmen.
Webdeb

if (this.title.length === 0) {sollte sein this.state.title.length, richtig?
Dmitry Minkovsky

4
Der erste Anwendungsfall ist wahrscheinlich keine gute Idee. setState-Rückrufe werden nach dem erneuten Rendern ausgelöst, sodass Sie ohne guten Grund ein doppeltes Rendern verursachen. Dies ist genau der Zweck des Funktionsarguments (Updater). Sie können einfach ausführen setState(state => state.title.length ? { titleError: "Title can't be blank" } : null)und die Änderung wird gestapelt. Keine Doppelrender erforderlich.
R Esmond

46
this.setState({
    name:'value' 
},() => {
    console.log(this.state.name);
});

14
Vielen Dank für dieses Code-Snippet, das möglicherweise nur begrenzte, sofortige Hilfe bietet. Eine richtige Erklärung würde ihren langfristigen Wert erheblich verbessern, indem sie zeigt, warum dies eine gute Lösung für das Problem ist, und es für zukünftige Leser mit anderen, ähnlichen Fragen nützlicher machen. Bitte bearbeiten Sie Ihre Antwort, um eine Erklärung hinzuzufügen, einschließlich der von Ihnen getroffenen Annahmen.
Machavity

1
Wenn Sie eine Funktion aufrufen möchten, nachdem sich der Status geändert hat, können Sie die Methode verwenden.
Araz Babayev

Was ist, wenn Sie mehrere Statusbereiche wie Name, Vorname usw. festlegen möchten?
Sumanth Varada

44

Der 1. Anwendungsfall, der mir in den Sinn kommt, ist ein apiAufruf, der nicht in das Rendering eingehen sollte, da er für eine Statusänderung ausgeführt wird each. Der API-Aufruf sollte nur bei einer speziellen Statusänderung und nicht bei jedem Rendern ausgeführt werden.

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

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

Daher kann für jede Statusänderung eine Aktion im Render-Methodenkörper ausgeführt werden.

Sehr schlechte Praxis , da die render-Methode rein sein sollte, bedeutet dies, dass keine Aktionen, Statusänderungen oder API-Aufrufe ausgeführt werden sollten. Fügen Sie einfach Ihre Ansicht zusammen und geben Sie sie zurück. Aktionen sollten nur für einige Ereignisse ausgeführt werden. Rendern ist kein Ereignis, sondern componentDidMountzum Beispiel.


25

Betrachten Sie den setState-Aufruf

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

IDEE

setState kann in asynchroner Funktion aufgerufen werden

Sie können sich also nicht darauf verlassen this. Wenn der obige Aufruf innerhalb einer asynchronen Funktion ausgeführt wurde this, bezieht sich dies auf den Status der Komponente zu diesem Zeitpunkt, aber wir haben erwartet, dass dies auf die Eigenschaft innerhalb des Status zum Zeitpunkt des Aufrufs von setState oder des Beginns der asynchronen Task verweist. Und da die Aufgabe ein asynchroner Aufruf war, hat sich diese Eigenschaft möglicherweise im Laufe der Zeit geändert. Daher ist die Verwendung unzuverlässigthis Schlüsselwort zu verwenden, um auf eine Eigenschaft des Status zu verweisen. wir eine Rückruffunktion, deren Argumente previousState und Requisiten sind. Dies bedeutet, dass die asynchrone Aufgabe ausgeführt wurde und es Zeit war, den Status mithilfe des setState-Aufrufs zu aktualisieren. PrevState bezieht sich jetzt auf den Status, wenn setState hat noch nicht begonnen. Sicherstellen, dass nextState nicht beschädigt wird.

Falscher Code: würde zur Beschädigung von Daten führen

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

Korrekter Code mit setState mit Rückruffunktion:

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

Wenn wir also unseren aktuellen Status basierend auf dem Wert, den die Eigenschaft gerade besitzt, auf den nächsten Status aktualisieren müssen und dies alles auf asynchrone Weise geschieht, ist es eine gute Idee, setState als Rückruffunktion zu verwenden.

Ich habe versucht, es hier im Codepen CODE PEN zu erklären

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.