- Der Zustand von React muss als unveränderlich behandelt werden, Aktualisierungen sollten über Setter und nicht durch direkte Mutation erfolgen, insbesondere bei Objekten und Arrays.
- Zustandsaktualisierungen erfolgen asynchron und können gebündelt werden. Durch die Verwendung funktionaler Aktualisierungsmechanismen lassen sich Probleme mit veralteten Zuständen in Timern, Closures und schnellen Interaktionen vermeiden.
- Funktionskomponenten mit Hooks (useState, useRef und ähnliche) sind der moderne Standard, während Tools wie React.memo und Immer bei der Performance und der Verarbeitung verschachtelter Daten helfen.
- Die klare Trennung von Eigenschaften und Zustand sowie ein Top-Down-Datenflussmodell sorgen dafür, dass das Verhalten der Komponenten auch bei wachsender Anwendung vorhersehbar bleibt.

State ist eines jener React-Konzepte, die auf den ersten Blick einfach erscheinen, aber mit zunehmender Größe der App schnell kompliziert werden. Man beginnt mit einem kleinen Zähler und jongliert plötzlich mit mehreren Formularfeldern, asynchronen Aktualisierungen, verschachtelten Objekten und Performance-Problemen, wenn alles gleichzeitig neu gerendert wird. Ein tiefes Verständnis des Zustands unterscheidet jemanden, der „React verwendet“, von jemandem, der reale React-Anwendungen skalieren und debuggen kann.
In diesem Leitfaden gehen wir den aktuellen Stand der Dinge in React durch (Wortspiel beabsichtigt), von Klassenkomponenten und Lebenszyklusmethoden bis hin zu modernen Hooks und unveränderlichen Aktualisierungen. Wir werden uns auch mit subtilen, aber wichtigen Themen wie asynchronen Aktualisierungen, veralteten Closures, der Verwendung von `useRef` anstelle von `useState` und der Vorhersagbarkeit Ihrer Benutzeroberfläche befassen. Ziel ist es, Ihnen ein klares mentales Modell zu vermitteln, damit sich Ihre Komponenten genau so verhalten, wie Sie es erwarten.
Von Requisiten zu Zuständen: Was gehört eigentlich wohin?
Im Kern jeder React-Komponente gibt es zwei Hauptdatenquellen: Props und State. Requisiten werden von der übergeordneten Komponente übergeben und bleiben für die Dauer des jeweiligen Renderings unverändert, während Zustand wird vom Bauteil selbst besessen und kontrolliert und ist für Daten gedacht, die sich im Laufe der Zeit ändern.
Eine gute Faustregel lautet: Werden Daten von außerhalb konfiguriert und ändern sie sich in dieser Komponente nicht, handelt es sich um eine Prop; muss die Komponente sie verfolgen und aktualisieren, handelt es sich um einen State. Stellen Sie sich eine blinkende Textkomponente vor: Der eigentliche Text wird einmalig bereitgestellt (eine Prop), aber ob er gerade angezeigt oder ausgeblendet ist, ändert sich ständig (der Zustand). Diese Unterscheidung ermöglicht es React, den Datenfluss vorhersehbar und unidirektional zu gestalten.
React fördert einen Top-Down-Datenfluss (unidirektional), bei dem der Zustand im nächstgelegenen gemeinsamen Vorfahren liegt, der ihn kontrollieren muss. Eine übergeordnete Komponente kann einen Zustand speichern und Werte als Props an untergeordnete Komponenten weitergeben, die diese rendern oder transformieren können, aber nicht wissen müssen, ob diese Werte ursprünglich aus dem Zustand, anderen Props stammen oder fest codiert wurden.
Deshalb hört man oft, dass der Zustand „lokal“ oder „abgekapselt“ ist. Nur die Komponente, die einen Zustand verwaltet, kann diesen ändern, und alle von diesem Zustand abgeleiteten UI-Elemente werden über die Props weitergegeben. Zustandsbehaftete und zustandslose (reine) Komponenten lassen sich beliebig kombinieren; ob eine Komponente zustandsbehaftet ist, ist eine Implementierungsfrage, die sich im Laufe der Zeit ändern kann.
Klassenkomponenten: Zustand und Lebenszyklus auf die altbewährte Art
Vor Hooks war die einzige Möglichkeit, Zustands- und Lebenszyklusmethoden in React zu verwenden, die Verwendung von ES6-Klassenkomponenten. Obwohl die meisten modernen Anwendungen auf Funktionskomponenten setzen, findet man in vielen Codebasen immer noch Klassenkomponenten (die man manchmal auch pflegen muss). Daher lohnt es sich, deren Funktionsweise zu verstehen.
Um eine Funktionskomponente wie eine einfache Clock Wenn man in einen Kurs geht, befolgt man einige mechanische Schritte. Sie erstellen eine Klasse, die erweitert React.Component, füge hinzu ein render() Methode, verschieben Sie den Funktionskörper in renderersetzen props und this.propsund löschen Sie die ursprüngliche Funktion. Solange React weiterhin rendert. <Clock /> Wird derselbe DOM-Knoten verwendet, wird eine einzelne Instanz dieser Klasse wiederverwendet.
Das Hinzufügen eines lokalen Zustands zu einer Klasse bedeutet, einen Konstruktor zu definieren und einen Anfangswert zuzuweisen. this.state Objekt. Zum Beispiel könnten Sie ein date Werte aus Props in den State umwandeln, indem ein Konstruktor hinzugefügt wird, der Folgendes aufruft super(props) und Sätze this.state = { date: new Date() }dann jegliche Verwendung von this.props.date in render() und this.state.dateDenken Sie daran, dass Sie in Klassenkomponenten nur direkt zuweisen sollten. this.state innerhalb des Konstruktors.
Lebenszyklusmethoden sind spezielle Klassenmethoden, die React zu bestimmten Zeitpunkten im Lebenszyklus einer Komponente aufruft. Wenn eine Komponente zum ersten Mal in das DOM eingefügt (montiert) wird, ruft React Folgendes auf: componentDidMount()Wenn es entfernt (unmountet) wird, ruft React Folgendes auf: componentWillUnmount()Im klassischen Beispiel mit der tickenden Uhr stellt man einen Timer ein in componentDidMount und es in componentWillUnmount, Speichern der Timer-ID auf this (zum Beispiel this.timerId) und rufen this.setState() jede Sekunde die Uhrzeit aktualisieren.
Der typische Lebenszyklus dieser Uhr sieht folgendermaßen aus: React ruft den Konstruktor auf, um den Zustand zu initialisieren, dann render() um das DOM zu erzeugen, dann componentDidMount() Dort, wo Sie den Timer starten. Jedes Mal, wenn der Timer auslöst, rufen Sie auf setState(), wodurch eine Aktualisierung in die Warteschlange gestellt und ausgelöst wird render() mit dem neuen Zustand. Sobald die Komponente entfernt wurde, componentWillUnmount() Löscht den Timer, damit keine Ressourcen verloren gehen.
Die korrekte Zustandsverwaltung in Klassen bedeutet auch, drei wichtige Regeln zu beachten. setState. Du darfst nicht mutieren this.state Sie müssen sich vor allem darüber im Klaren sein, dass Aktualisierungen asynchron und in Batches erfolgen können und dass Aktualisierungen nur oberflächlich zusammengeführt werden (nur die Status-Schlüssel der obersten Ebene werden zusammengeführt, nicht tief verschachtelte Objekte).
Zustandsverwaltung korrekt: Mutationen, asynchrone Aktualisierungen und Datenfluss
Eine der größten Verwirrungsquellen für Anfänger ist, dass setState (und das entsprechende Hook-Äquivalent) aktualisiert den Zustand nicht sofort, und Sie sollten Zustandsobjekte niemals direkt ändern. React fasst aus Performancegründen oft mehrere Aktualisierungen zusammen, daher beide this.state In Klassen und Zustandsvariablen in Hooks wird der endgültige Zustand möglicherweise nicht direkt nach der geplanten Aktualisierung widergespiegelt.
Direkte Zustandsänderung, wie zum Beispiel this.state.count++ oder das Ändern von Eigenschaften eines Zustandsobjekts, überspringt die Änderungsermittlung von React und kann dazu führen, dass Komponenten bei alten Werten hängen bleiben. React erwartet, dass Sie jedes Objekt im Zustand als schreibgeschützt behandeln. Anstatt bestehende Objekte zu ändern, erstellen Sie ein neues Objekt oder Array mit den gewünschten Änderungen und übergeben dieses an den Zustandsaktualisierungsmechanismus.
Da Zustandsaktualisierungen asynchron erfolgen können, ist beim Berechnen des nächsten Zustands aus dem vorherigen besondere Vorsicht geboten. Im Unterricht so etwas wie this.setState({ count: this.state.count + 1 }) kann zu Fehlern führen, wenn mehrere Aktualisierungen gebündelt werden. Die Lösung besteht in der Verwendung der funktionalen Form: this.setState((prevState, props) => ({ count: prevState.count + 1 }))Dadurch wird garantiert, dass Sie mit dem aktuellsten Zustands-Snapshot arbeiten.
Das gleiche Muster gibt es auch bei Hooks: Man kann den Updater mit einer Funktion anstelle eines Wertes aufrufen. Zum Beispiel, setCount(prev => prev + 1) ist die sicherere Methode, einen Zähler zu erhöhen, wenn der neue Wert vom vorherigen abhängt oder wenn Aktualisierungen innerhalb von Timern oder Ereignisbehandlern erfolgen könnten, die später ausgeführt werden.
Auch wenn der Zustand „lokal“ ist, breitet sich die Auswirkung einer Zustandsänderung immer durch den Komponentenbaum aus. Ein durch eine Zustandsaktualisierung ausgelöstes erneutes Rendern des übergeordneten Elements führt standardmäßig auch zum erneuten Rendern aller seiner untergeordneten Elemente. Dieser Top-Down-Datenfluss ist grundlegend für das mentale Modell von React: eine zentrale Datenquelle an der Spitze, von der die Benutzeroberfläche abgeleitet wird.
Modernes React: Hooks und Funktionskomponenten
Seit React 16.8 sind Hooks zum Standardverfahren für die Verwaltung von Zustand und Seiteneffekten in Funktionskomponenten geworden. Sie ermöglichen es Ihnen, dieselben Funktionen wie Klassenkomponenten (und mehr) zu nutzen, ohne Klassen schreiben oder sich mit ... auseinandersetzen zu müssen. this und Lebenszyklusmethoden explizit, apoyándose en el Es ist ein moderner JavaScript-Status.
Funktionskomponenten sind mittlerweile der Standardstil in React-Codebasen. Anstatt zu schreiben class Example extends React.ComponentSie definieren eine einfache Funktion wie function Example() { return <div />; }Wenn Sie Zustand, Seiteneffekte oder Referenzen benötigen, „haken“ Sie sich über Funktionen wie `react.hash()` in React ein. useState, useEffect , useRefHooks können nicht innerhalb von Klassen verwendet werden und müssen die Hook-Regeln beachten (rufen Sie sie immer auf der obersten Ebene Ihrer Komponente auf, niemals in Schleifen oder Bedingungen).
Das useState Hook ist die einfachste Möglichkeit, einem Funktionsbaustein einen lokalen Zustand hinzuzufügen. Es nimmt den Anfangswert als Argument und gibt ein Paar zurück: den aktuellen Zustandswert und eine Setter-Methode. Dank Array-Destrukturierung schreibt man üblicherweise so etwas wie const = useState(0)React speichert diesen Zustand zwischen erneuten Renderings, was bedeutet, dass die Funktion zwar mehrmals aufgerufen werden kann, der Zustandswert aber erhalten bleibt.
Im Gegensatz zum Klassenzustand wird der Wert, den Sie speichern, in useState Es muss sich nicht um ein Objekt handeln. Sie können Zahlen, Zeichenketten, boolesche Werte, Arrays oder Objekte speichern – je nachdem, was zu den Daten passt. Wenn Sie mehrere unabhängige Werte benötigen, können Sie Folgendes aufrufen: useState mehrmals (zum Beispiel age, fruit, todosAlternativ können Sie ein einzelnes Objekt speichern und mehrere Eigenschaften darin verwalten, müssen aber beim Aktualisieren die Unveränderlichkeitsregeln beachten.
Wenn Sie die von zurückgegebene Setter-Funktion aufrufen useStateSie ändern den Wert nicht synchron; Sie reihen eine Aktualisierung in eine Warteschlange ein, genau wie bei setState im Unterricht. Beim nächsten Rendern weist React Ihrer Komponente den neuen Zustandswert zu. Deshalb erhalten Sie beim Auslesen des Zustands direkt nach dem Aufruf der Setter-Methode innerhalb derselben synchronen Funktion immer noch den alten Wert.
Objekte und verschachtelte Daten im Zustand verwalten
Mit React können Sie beliebige JavaScript-Werte im Zustand speichern, einschließlich Objekte und Arrays, aber Sie müssen diese als unveränderliche Momentaufnahmen behandeln. Primitive Werte wie Zahlen und Zeichenketten können ohnehin nicht verändert werden, Objekte und Arrays hingegen schon – allerdings würde eine Veränderung dieser Datentypen die Annahmen von React verletzen und zu subtilen Fehlern führen, bei denen Komponenten nicht aktualisiert werden.
Betrachten wir ein Zustandsobjekt wie { x: 0, y: 0 } stellt eine Zeigerposition dar. Wenn du schreibst position.x = event.clientX Direkt haben Sie das bestehende Objekt verändert. React merkt nicht, dass sich der Wert geändert hat, da Sie die Setter-Methode nicht aufgerufen haben. Daher wird die Seite nicht neu gerendert und die Benutzeroberfläche bleibt blockiert. Der korrekte Ansatz ist: setPosition({ x: event.clientX, y: event.clientY })Dadurch wird ein brandneues Objekt erzeugt und React angewiesen, damit zu rendern.
Lokale Mutationen von neu erstellten Objekten sind völlig in Ordnung. Man kann beispielsweise ein neues Objekt Schritt für Schritt aufbauen: const next = { ...prev }; next.city = 'Paris'; solange next Der Zustand war noch nicht vorhanden. Eine Mutation wird erst dann zum Problem, wenn Sie ein Objekt ändern, das bereits in einem vorherigen Zustands-Snapshot verwendet wurde, da andere Teile Ihrer Anwendung möglicherweise noch auf diesen alten Wert angewiesen sind.
Um nur einen Teil eines Objekts zu aktualisieren und den Rest beizubehalten, verwendet man typischerweise die Objekt-Spread-Syntax. Für ein Formularstatusobjekt wie { firstName, lastName, email }Sie könnten Eingabeänderungen beispielsweise so handhaben: setPerson({ ...person, : event.target.value })Dadurch werden die alten Eigenschaften kopiert und anschließend nur die geänderte Eigenschaft überschrieben. Da die Spread-Operation flach ist, erfordern verschachtelte Objekte besondere Aufmerksamkeit.
Tief verschachtelte Objekte können schnell zu umfangreichem Aktualisierungscode führen, da Sie auf jeder Ebene des zu ändernden Pfades neue Kopien erstellen müssen. Zum Beispiel, wenn person.artwork.city Änderungen, die Sie vornehmen würden setPerson({ ...person, artwork: { ...person.artwork, city: 'London' } })Intern gibt es keine „verschachtelten Objekte“, sondern separate Objekte, die aufeinander verweisen. Wenn also mehrere Elternobjekte auf dasselbe Kindobjekt verweisen und Sie dieses verändern, ändern Sie die Daten an mehr als einer Stelle gleichzeitig.
Wenn Sie ständig verschachtelte Tabellen schreiben müssen, sollten Sie vielleicht erwägen, Ihre Zustandsstruktur zu vereinfachen oder eine Hilfsbibliothek wie Immer zu verwenden. Mit Immer können Sie Code schreiben, der mutive aussieht (wie draft.artwork.city = 'London') während im Hintergrund eine neue, unveränderliche Kopie für Sie erstellt wird. In React können Sie Immer mit Hooks kombinieren über useImmer von der use-immer Paket.
Staat in der Praxis: Formulare, Timer und Benutzereingaben
In realen Anwendungen verwaltet man den Zustand selten nur für Zähler; man verwaltet Benutzereingaben, API-Antworten und UI-"Modi" wie Laden, Fehler und Erfolg. Der entscheidende Mentalitätswandel bei React besteht darin, dass man nicht „das DOM manipuliert“ (zum Beispiel „diesen Button deaktivieren“); stattdessen beschreibt man, wie die Benutzeroberfläche für jeden Zustand aussehen soll, und aktualisiert dann den Zustand.
Beispielsweise könnte eine Quiz- oder Formularkomponente Folgendes erfassen: status Zustand, der zwischen 'typing', 'submitting' , 'success'. Der JSX-Code deaktiviert den Absenden-Button während des Absendens und zeigt eine Erfolgsmeldung an, sobald die Antwort korrekt ist. Es werden keine imperativen DOM-Methoden aufgerufen – React rendert die Seite einfach mit dem neuen Zustand neu, und die visuelle Ausgabe ändert sich.
Die Bearbeitung von Formularfeldern ist der Punkt, an dem viele Entwickler zum ersten Mal auf den Unterschied zwischen dem Zusammenführen von Klassenzuständen und useState Verhalten. In einer Klasse setState Das übergebene Objekt wird in das bestehende Statusobjekt integriert, sodass die Aktualisierung eines Feldes die anderen nicht löscht. useStateAktualisierungen ersetzen den gesamten Wert: Wenn Ihr Zustand ein Objekt ist und Sie aufrufen setState({ email: '...' }), alle anderen Eigenschaften (wie password) verschwinden, sofern Sie sie nicht manuell zusammenführen.
Dieser Unterschied führt oft zu Verwirrung, wenn man von mehreren primitiven Zustandsvariablen zu einem einzigen Objekt refaktoriert. Wenn Sie von const , const zu const und dann einen generischen setForm({ : value })Sie erhalten dann ein Zustandsobjekt, das immer nur ein Feld besitzt. Die Lösung besteht darin, das vorherige Objekt zu verteilen: setForm({ ...form, : value }).
In komplexeren Anwendungen werden Sie oft nicht anrufen setState (oder setSomething) direkt von überall. Sie könnten den Zustand mithilfe von Bibliotheken wie Redux oder MobX zentralisieren oder die useReducer Hook für Zustandsautomaten auf Komponentenebene. In diesen Setups gelten weiterhin die gleichen Unveränderlichkeitsprinzipien; der einzige Unterschied besteht darin, wo und wie Aktualisierungen durchgeführt werden.
Neu-Renderings, Performance und wann useRef verwendet werden sollte
Jede Zustandsaktualisierung in React löst ein erneutes Rendern der Komponente aus, die den Zustand besitzt, und standardmäßig auch aller ihrer Kinder. Dies ist so beabsichtigt: Durch das erneute Rendern bleibt Ihre Benutzeroberfläche mit den aktuellen Daten synchron. Das bedeutet aber auch, dass eine unüberlegte Platzierung des Zustands unnötige Arbeit und träge Benutzeroberflächen verursachen kann, insbesondere wenn untergeordnete Komponenten aufwändige Berechnungen durchführen oder große Listen rendern.
Stellen Sie sich eine App mit einem Eingabefeld und einer separaten Komponente vor, die eine lange Liste von Fähigkeiten anzeigt. Wenn die übergeordnete Komponente sowohl den vom Benutzer eingegebenen Text als auch die Liste selbst enthält, wird bei jedem Tastendruck der gesamte Baum neu gerendert, einschließlich der Fertigkeitenliste, obwohl sich diese nicht geändert hat. Das ist unnötige Arbeit.
Eine einfache Möglichkeit zur Optimierung besteht darin, Kindkomponenten in ... einzuschließen. React.memo. React.memo ist eine Komponente höherer Ordnung, die das Ergebnis einer Funktionskomponente speichert: Wenn ihre Props zwischen den Renderings gleich sind, überspringt React das erneute Rendern. Ihre Skill-List-Komponente, einmal in ein solches Element eingebettet, … React.memoDie Seite wird nicht bei jedem Tastendruck neu gerendert – nur wenn… skills Die Eigenschaften ändern sich tatsächlich (zum Beispiel, wenn man eine neue Fähigkeit hinzufügt).
Nicht alle „zustandsähnlichen“ Daten gehören dazu useState; manchmal useRef ist das bessere Werkzeug. Das useRef Hook liefert Ihnen ein veränderliches Objekt mit einem current Eine Eigenschaft, die für die gesamte Lebensdauer der Komponente erhalten bleibt, deren Aktualisierung jedoch … kein Frontalunterricht. Es löst ein erneutes Rendern aus. Dadurch eignet es sich perfekt zum Speichern von Dingen wie Timer-IDs, DOM-Elementreferenzen oder Zählern, die Sie zwar verfolgen möchten, aber nicht in der Benutzeroberfläche anzeigen müssen.
Ein einfaches Beispiel ist ein Zähler, der mit useRef statt useState. Wenn Sie die Anzahl speichern in countRef.current Wird der Wert in einem Ereignishandler erhöht, ändert sich zwar der interne Wert, aber das angezeigte JSX wird nicht aktualisiert, da React nicht neu gerendert hat. Dies verdeutlicht den entscheidenden Unterschied: useState dient der Darstellung von Werten, die die Benutzeroberfläche steuern; useRef dient zur Speicherung von Werten, die Sie beibehalten möchten, ohne die Darstellung zu beeinflussen.
Unveränderlichkeit und warum direkte Mutation eine Falle ist
Ein grundlegendes Prinzip in React ist, dass Zustandsaktualisierungen unveränderlich sein müssen. Das heißt nicht, dass man nie etwas ändern kann; es bedeutet, dass man anstatt bestehende Werte (insbesondere Objekte und Arrays) zu verändern, neue Werte erstellt und die alten als historische Momentaufnahmen der Benutzeroberfläche beibehält.
Durch die direkte Veränderung des Zustands wird die Verbindung zwischen Ihrem mentalen Modell und dem, was React tut, unterbrochen. Wenn Sie so etwas tun wie state.count++ Wenn du den Wert direkt in ein Zustandsarray schreibst, merkt React nicht, dass sich etwas geändert hat, da du die Updater-Funktion nicht aufgerufen hast. Der interne Snapshot, den React verwendet, um zu entscheiden, wann neu gerendert werden soll, bleibt unverändert, während dein Code annimmt, der Wert habe sich geändert. So entstehen Fehler, die sich beim Neuladen scheinbar von selbst beheben.
Sie sollten außerdem vermeiden, einer anderen Variablen einen Zustandswert zuzuweisen und diese Variable anschließend zu verändern. Zum Beispiel, indem man Folgendes tut const newCount = count; newCount++; Verändert weiterhin denselben zugrunde liegenden Wert für primitive Datentypen und Objekte. const copy = stateObj; Es wird überhaupt keine Kopie erstellt – es wird lediglich eine weitere Referenz auf dasselbe Objekt erzeugt. Korrektes Kopieren erfordert Muster wie { ...stateObj } für Objekte oder für Arrays.
Bibliotheken wie Redux, MobX (wenn sie auf Unveränderlichkeit konfiguriert sind) oder Immer existieren unter anderem, um unveränderliche Muster durchzusetzen oder zu vereinfachen. Egal ob Sie die integrierten Hooks von React oder eine State-Management-Bibliothek verwenden, die goldene Regel bleibt bestehen: Verändern Sie niemals den bestehenden Zustand direkt, wenn Sie erwarten, dass React die Änderung erkennt und neu rendert.
Asynchrone Aktualisierungen, Stapelverarbeitung und veralteter Zustand
Ein subtiles, aber entscheidendes Detail beim React-Zustand ist, dass Aktualisierungen asynchron und geplant erfolgen und nicht sofort angewendet werden. Wenn du anrufst setState oder ein Hakensetzer wie setCountReact reiht ein erneutes Rendern für einen späteren Zeitpunkt in die Warteschlange ein. Dadurch wird Ihr Code nicht sofort blockiert, um zu aktualisieren und neu zu rendern. React kann so mehrere Aktualisierungen bündeln und eine reibungslose Performance gewährleisten.
Dieses Scheduling-Modell bedeutet, dass man sich nicht darauf verlassen kann, den Zustand unmittelbar nach dem Aufruf des Updaters innerhalb desselben synchronen Blocks zu lesen. Der Wert, den Sie erhalten, ist in der Regel der alte Snapshot. Stattdessen sollten Sie den Updater als Anfrage betrachten: „Verwenden Sie beim nächsten Rendern diesen Wert (oder diese Transformationsfunktion)“.
Dies ist besonders wichtig, wenn Sie den Zustand innerhalb von Closures basierend auf seinem aktuellen Wert aktualisieren, wie zum Beispiel setTimeout oder Rückrufe im Rahmen des Abonnements. Diese Rückruffunktionen erfassen den Zustand zum Zeitpunkt ihrer Erstellung. Wenn Sie dann Folgendes tun: setCount(count + 1) innerhalb einer Auszeit, count Die von Ihnen erwähnten Daten könnten veraltet sein, wenn der Callback tatsächlich ausgeführt wird.
Dieses Phänomen wird als „Stale State“ oder „Stale Closures“ bezeichnet. Wenn Sie beispielsweise einen Button haben, der beim Klicken eine Funktion aufruft, die ein Timeout festlegt und dann nach einer Sekunde den Zustand erhöht, kann es bei mehreren schnellen Klicks vorkommen, dass der Zustand nicht korrekt erhöht wird. Jeder Timeout-Callback verwendet die alte Methode. count Es wurde erfasst, wann die Zeitüberschreitung geplant war.
Die robuste Lösung besteht darin, die funktionale Updater-Form Ihres State-Setters zu verwenden. Anstelle von setCount(count + 1) Innerhalb der Auszeit schreiben Sie setCount(prevCount => prevCount + 1)Jeder Callback erhält nun den zuletzt verwendeten Wert zum Zeitpunkt der Aktualisierung und nicht mehr den Wert, der beim Erstellen des Timeouts gültig war. Dadurch wird das Problem des veralteten Zustands behoben, ohne das Verhalten Ihrer Closures anderweitig zu ändern.
Die React-Dokumentation weist auch auf ein weniger bekanntes Detail hin: Wenn Ihr funktionaler Updater nichts zurückgibt (undefined), wird React das erneute Rendern überspringen. Das bedeutet, dass Ihre Aktualisierungsfunktionen immer den nächsten Zustandswert zurückgeben (oder den vorherigen wiederverwenden) sollten, es sei denn, Sie möchten eine Aktualisierung explizit verhindern – was bei Standardarchitekturen selten wünschenswert ist. useState Verwendung.
Das Verständnis dieser Kombination aus asynchroner Planung, Batchverarbeitung und Closure-Verhalten ist entscheidend für das Schreiben zuverlässiger Zustandslogik in Anwendungen, die mit Timeouts, Intervallen, Abonnements oder schnellen Benutzerinteraktionen zu tun haben. Sobald man verinnerlicht hat, dass Zustandssetzer Aktualisierungen planen, anstatt sie sofort auszuführen, ergeben Fehler, die sich zuvor zufällig anfühlten, plötzlich Sinn.
Wenn man all diese Ideen zusammen betrachtet – Eigenschaften vs. Zustand, Klassenlebenszyklen vs. Hooks, Unveränderlichkeit, kontrollierte Komponenten, useRef Für nicht-visuelle Werte, Memoization, asynchrone Aktualisierungen und veraltete Closures erhält man ein leistungsstarkes, vorhersagbares Modell dafür, wie sich React-UIs im Laufe der Zeit weiterentwickeln. Anstatt in Kategorien imperativer DOM-Änderungen zu denken, entwerfen Sie klare Zustandsmodelle und überlassen React das erneute Rendern. Dadurch werden Ihre Komponenten leichter verständlich, testbar und erweiterbar, wenn Ihre Anwendung wächst.
