Ich arbeite an React.
TLDR:
Aber können Sie darauf vertrauen, dass React den Status in der Reihenfolge aktualisiert, in der setState aufgerufen wird?
Ja.
- verschiedene Komponenten?
Ja.
Die Reihenfolge der Updates wird immer eingehalten. Ob Sie einen Zwischenzustand "zwischen" ihnen sehen oder nicht, hängt davon ab, ob Sie sich in einem Stapel befinden oder nicht.
Derzeit (React 16 und früher) werden standardmäßig nur Aktualisierungen in React-Ereignishandlern gestapelt . Es gibt eine instabile API, um das Batching außerhalb von Ereignishandlern in seltenen Fällen zu erzwingen, wenn Sie es benötigen.
In zukünftigen Versionen (wahrscheinlich React 17 und höher) stapelt React standardmäßig alle Updates, sodass Sie nicht darüber nachdenken müssen. Wie immer werden wir diesbezügliche Änderungen im React-Blog und in den Versionshinweisen bekannt geben.
Der Schlüssel zum Verständnis ist, dass unabhängig davon, wie viele setState()
Aufrufe in wie vielen Komponenten Sie in einem React-Ereignishandler ausführen , am Ende des Ereignisses nur ein einziges erneutes Rendern erzeugt wird . Dies ist entscheidend für eine gute Leistung in großen Anwendungen , denn wenn Child
und Parent
jeden Anruf , setState()
wenn einem Klick Event - Handling, Sie wollen nicht wieder machen die Child
zweimal.
In beiden Beispielen werden setState()
Aufrufe in einem React-Ereignishandler ausgeführt. Daher werden sie am Ende des Ereignisses immer zusammengespült (und Sie sehen den Zwischenzustand nicht).
Die Aktualisierungen werden immer flach in der Reihenfolge zusammengeführt, in der sie auftreten . Wenn also das erste Update ist {a: 10}
, ist das zweite {b: 20}
und das dritte ist {a: 30}
der gerenderte Zustand {a: 30, b: 20}
. Das neuere Update auf denselben Statusschlüssel (z. B. wie a
in meinem Beispiel) "gewinnt" immer.
Das this.state
Objekt wird aktualisiert, wenn die Benutzeroberfläche am Ende des Stapels erneut gerendert wird. Wenn Sie also den Status basierend auf einem vorherigen Status aktualisieren müssen (z. B. das Inkrementieren eines Zählers), sollten Sie die Funktionsversion verwenden setState(fn)
, die den vorherigen Status angibt, anstatt aus zu lesen this.state
. Wenn Sie neugierig auf die Gründe dafür sind, habe ich dies in diesem Kommentar ausführlich erläutert .
In Ihrem Beispiel wird der "Zwischenstatus" nicht angezeigt, da wir uns in einem React-Ereignishandler befinden, in dem die Stapelverarbeitung aktiviert ist (weil React "weiß", wann wir dieses Ereignis beenden).
Sowohl in React 16 als auch in früheren Versionen gibt es jedoch außerhalb der React-Ereignishandler standardmäßig noch keine Stapelverarbeitung . Wenn wir in Ihrem Beispiel stattdessen einen AJAX-Antworthandler hätten handleClick
, setState()
würde jeder sofort verarbeitet, sobald dies geschieht. In diesem Fall ja, man würde einen Zwischenzustand sehen:
promise.then(() => {
// We're not in an event handler, so these are flushed separately.
this.setState({a: true}); // Re-renders with {a: true, b: false }
this.setState({b: true}); // Re-renders with {a: true, b: true }
this.props.setParentState(); // Re-renders the parent
});
Wir wissen, dass es unpraktisch ist, dass das Verhalten unterschiedlich ist, je nachdem, ob Sie sich in einem Event-Handler befinden oder nicht . Dies wird sich in einer zukünftigen React-Version ändern, die standardmäßig alle Updates stapelt (und eine Opt-In-API bereitstellt, um Änderungen synchron zu löschen). Bis wir das Standardverhalten ändern (möglicherweise in React 17), gibt es eine API, mit der Sie das Batching erzwingen können :
promise.then(() => {
// Forces batching
ReactDOM.unstable_batchedUpdates(() => {
this.setState({a: true}); // Doesn't re-render yet
this.setState({b: true}); // Doesn't re-render yet
this.props.setParentState(); // Doesn't re-render yet
});
// When we exit unstable_batchedUpdates, re-renders once
});
Intern React-Ereignishandler werden alle eingeschlossen, unstable_batchedUpdates
weshalb sie standardmäßig gestapelt sind. Beachten Sie, dass das unstable_batchedUpdates
zweimalige Umschließen eines Updates keine Auswirkungen hat. Die Aktualisierungen werden gelöscht, wenn wir den äußersten unstable_batchedUpdates
Anruf beenden .
Diese API ist "instabil" in dem Sinne, dass wir sie entfernen, wenn die Stapelverarbeitung bereits standardmäßig aktiviert ist. Wir werden es jedoch in einer Nebenversion nicht entfernen, sodass Sie sich bis React 17 sicher darauf verlassen können, wenn Sie in einigen Fällen das Stapeln außerhalb der React-Ereignishandler erzwingen müssen.
Zusammenfassend ist dies ein verwirrendes Thema, da standardmäßig nur Stapel in Ereignishandlern reagieren. Dies wird sich in zukünftigen Versionen ändern, und das Verhalten wird dann einfacher sein. Die Lösung besteht jedoch nicht darin, weniger zu stapeln , sondern standardmäßig mehr zu stapeln. Das werden wir tun.