Auswahl der State-Struktur
Eine gut strukturierte State kann den Unterschied ausmachen zwischen einer Komponente, die angenehm zu ändern und zu debuggen ist, und einer, die eine ständige Fehlerquelle darstellt. Hier sind einige Tipps, die Sie bei der Strukturierung des States berücksichtigen sollten.
Sie werden lernen
- Wann eine einzelne gegenüber mehreren State-Variablen verwendet werden sollte
- Was bei der Organisation des States zu vermeiden ist
- Wie häufige Probleme mit der State-Struktur behoben werden können
Prinzipien für die Strukturierung des States
Wenn Sie eine Komponente schreiben, die einen State hält, müssen Sie Entscheidungen darüber treffen, wie viele State-Variablen verwendet werden sollen und wie die Form ihrer Daten aussehen sollte. Auch wenn es möglich ist, korrekte Programme selbst mit einer suboptimalen State-Struktur zu schreiben, gibt es einige Prinzipien, die Sie bei der Auswahl besserer Optionen leiten können:
- Gruppieren Sie zusammenhängenden State.Wenn Sie immer zwei oder mehr State-Variablen gleichzeitig aktualisieren, sollten Sie erwägen, sie in eine einzige State-Variable zusammenzuführen.
- Vermeiden Sie Widersprüche im State.Wenn der State so strukturiert ist, dass mehrere Teile des States sich widersprechen und „uneinig“ sein können, schaffen Sie Raum für Fehler. Versuchen Sie, dies zu vermeiden.
- Vermeiden Sie redundanten State.Wenn Sie einige Informationen aus den Props der Komponente oder ihren vorhandenen State-Variablen während des Renderings berechnen können, sollten Sie diese Informationen nicht in den State dieser Komponente aufnehmen.
- Vermeiden Sie Duplikate im State.Wenn dieselben Daten zwischen mehreren State-Variablen oder innerhalb verschachtelter Objekte dupliziert werden, ist es schwierig, sie synchron zu halten. Reduzieren Sie Duplikate, wann immer möglich.
- Vermeiden Sie tief verschachtelten State.Tief hierarchischer State ist nicht sehr bequem zu aktualisieren. Wenn möglich, bevorzugen Sie es, den State flach zu strukturieren.
Das Ziel hinter diesen Prinzipien ist es,den State einfach zu aktualisieren, ohne Fehler einzuführen. Das Entfernen von redundanten und duplizierten Daten aus dem State hilft sicherzustellen, dass alle seine Teile synchron bleiben. Dies ähnelt der Vorgehensweise eines Datenbankingenieurs, der die„Normalisierung“ der Datenbankstrukturanstrebt, um die Wahrscheinlichkeit von Fehlern zu verringern. Um Albert Einstein zu paraphrasieren:„Machen Sie Ihren State so einfach wie möglich – aber nicht einfacher.“
Sehen wir uns nun an, wie diese Prinzipien in der Praxis angewendet werden.
Gruppieren Sie zusammenhängenden State
Sie sind sich vielleicht manchmal unsicher, ob Sie eine einzelne oder mehrere State-Variablen verwenden sollen.
Sollten Sie das tun?
Oder das hier?
Technisch gesehen kannst du beide Ansätze verwenden. Aberwenn sich zwei Zustandsvariablen immer gemeinsam ändern, kann es sinnvoll sein, sie in einer einzigen Zustandsvariablen zusammenzufassen.Dann vergisst du nicht, sie immer synchron zu halten, wie in diesem Beispiel, bei dem die Bewegung des Cursors beide Koordinaten des roten Punkts aktualisiert:
Ein weiterer Fall, in dem du Daten in einem Objekt oder Array gruppierst, ist, wenn du nicht weißt, wie viele Zustandswerte du benötigst. Das ist zum Beispiel hilfreich, wenn du ein Formular hast, in dem der Nutzer benutzerdefinierte Felder hinzufügen kann.
Fallstrick
Wenn deine Zustandsvariable ein Objekt ist, denke daran, dassdu nicht nur ein Feld darin aktualisieren kannst, ohne die anderen Felder explizit zu kopieren. Du kannst zum Beispiel im obigen Beispiel nichtsetPosition({ x: 100 })aufrufen, weil dann die Eigenschaftyüberhaupt nicht vorhanden wäre! Stattdessen, wenn du nurxsetzen möchtest, würdest du entwedersetPosition({ ...position, x: 100 })aufrufen oder sie in zwei Zustandsvariablen aufteilen undsetX(100)aufrufen.
Widersprüche im Zustand vermeiden
Hier ist ein Hotel-Feedback-Formular mit den ZustandsvariablenisSendingundisSent:
Während dieser Code funktioniert, öffnet er die Tür für "unmögliche" Zustände. Wenn Sie beispielsweise vergessen,setIsSentundsetIsSendingzusammen aufzurufen, könnten Sie in eine Situation geraten, in der sowohlisSendingals auchisSentgleichzeitigtruesind. Je komplexer Ihre Komponente ist, desto schwieriger ist es zu verstehen, was passiert ist.
DaisSendingundisSentniemals gleichzeitigtruesein sollten, ist es besser, sie durch eine einzigestatus-Zustandsvariable zu ersetzen, die einen vondreigültigen Zuständen annehmen kann:'typing'(initial),'sending'und'sent':
Sie können weiterhin einige Konstanten für bessere Lesbarkeit deklarieren:
Aber es sind keine Zustandsvariablen, daher müssen Sie sich keine Sorgen machen, dass sie nicht mehr synchron zueinander sind.
Redundante Zustände vermeiden
Wenn Sie einige Informationen aus den Props der Komponente oder ihren vorhandenen Zustandsvariablen während des Renderings berechnen können,sollten Siediese Informationen nicht in den Zustand dieser Komponente aufnehmen.
Nehmen Sie zum Beispiel dieses Formular. Es funktioniert, aber können Sie einen redundanten Zustand darin finden?
Dieses Formular hat drei Zustandsvariablen:firstName,lastNameundfullName. Allerdings istfullNameredundant.Sie könnenfullNameimmer ausfirstNameundlastNamewährend des Renderns berechnen, also entfernen Sie es aus dem Zustand.
So können Sie es machen:
Hier istfullName keineZustandsvariable. Stattdessen wird sie während des Renderns berechnet:
Daher müssen die Event-Handler nichts Besonderes tun, um sie zu aktualisieren. Wenn SiesetFirstNameodersetLastNameaufrufen, lösen Sie ein erneutes Rendern aus, und dann wird der nächstefullNameaus den frischen Daten berechnet.
Duplikate im State vermeiden
Diese Menülisten-Komponente lässt dich einen einzelnen Reisesnack aus mehreren auswählen:
Derzeit speichert sie das ausgewählte Element als Objekt in der State-VariableselectedItem. Das ist jedoch nicht optimal:der Inhalt vonselectedItemist dasselbe Objekt wie eines der Elemente in der Listeitems.Das bedeutet, dass die Informationen über das Element selbst an zwei Stellen dupliziert sind.
Warum ist das ein Problem? Lass uns jedes Element bearbeitbar machen:
Beachte, dass wenn du zuerst auf „Choose“ bei einem Element klickst unddannes bearbeitest,sich die Eingabe aktualisiert, die Beschriftung unten jedoch die Bearbeitungen nicht widerspiegelt.Das liegt daran, dass du den State dupliziert hast und vergessen hast,selectedItemzu aktualisieren.
Obwohl du auchselectedItemaktualisieren könntest, ist eine einfachere Lösung, die Duplizierung zu entfernen. In diesem Beispiel hältst du statt einesselectedItem-Objekts (was eine Duplizierung mit Objekten initemserzeugt) dieselectedIdim State unddannerhältst du dasselectedItem, indem du dasitems-Array nach einem Element mit dieser ID durchsuchst:
Der Zustand war zuvor wie folgt dupliziert:
items = [{ id: 0, title: 'pretzels'}, ...]selectedItem = {id: 0, title: 'pretzels'}
Nach der Änderung sieht es jedoch so aus:
items = [{ id: 0, title: 'pretzels'}, ...]selectedId = 0
Die Duplizierung ist verschwunden, und Sie behalten nur den wesentlichen Zustand!
Wenn Sie nun dasausgewählteElement bearbeiten, wird die Nachricht unten sofort aktualisiert. Das liegt daran, dasssetItemsein erneutes Rendern auslöst unditems.find(...)das Element mit dem aktualisierten Titel finden würde. Sie musstendas ausgewählte Elementnicht im Zustand halten, weil nur dieausgewählte IDwesentlich ist. Der Rest konnte während des Renderns berechnet werden.
Vermeiden Sie tief verschachtelten Zustand
Stellen Sie sich einen Reiseplan vor, der Planeten, Kontinente und Länder umfasst. Sie könnten versucht sein, seinen Zustand mit verschachtelten Objekten und Arrays zu strukturieren, wie in diesem Beispiel:
Nehmen wir nun an, Sie möchten eine Schaltfläche hinzufügen, um einen bereits besuchten Ort zu löschen. Wie würden Sie vorgehen?Die Aktualisierung von verschachteltem Zustanderfordert das Erstellen von Kopien der Objekte von der geänderten Stelle aus nach oben. Das Löschen eines tief verschachtelten Ortes würde das Kopieren seiner gesamten übergeordneten Ortskette erfordern. Solcher Code kann sehr umfangreich sein.
Wenn der Zustand zu stark verschachtelt ist, um ihn einfach zu aktualisieren, sollten Sie ihn „flach“ gestalten.Hier ist eine Möglichkeit, diese Daten umzustrukturieren. Anstatt einer baumartigen Struktur, in der jederplaceein Array vonseinen untergeordneten Ortenhat, können Sie jeden Ort ein Array vonden IDs seiner untergeordneten Ortehalten lassen. Speichern Sie dann eine Zuordnung von jeder Orts-ID zum entsprechenden Ort.
Diese Datenumstrukturierung könnte Sie an eine Datenbanktabelle erinnern:
Da der State nun „flach“ (auch als „normalisiert“ bezeichnet) ist, wird das Aktualisieren verschachtelter Elemente einfacher.
Um nun einen Ort zu entfernen, müssen Sie nur zwei Ebenen des States aktualisieren:
- Die aktualisierte Version seinesEltern-Orts sollte die entfernte ID aus seinem
childIds-Array ausschließen. - Die aktualisierte Version des root „Tabellen“-Objekts sollte die aktualisierte Version des Eltern-Ortes enthalten.
Hier ist ein Beispiel, wie Sie dabei vorgehen könnten:
Sie können den State beliebig tief verschachteln, aber eine "flache" Struktur kann zahlreiche Probleme lösen. Sie erleichtert die Aktualisierung des States und hilft sicherzustellen, dass Sie keine Duplikate in verschiedenen Teilen eines verschachtelten Objekts haben.
Manchmal kannst du die Verschachtelung des States auch reduzieren, indem du einen Teil des verschachtelten States in die Kindkomponenten verschiebst. Das funktioniert gut für flüchtigen UI-State, der nicht gespeichert werden muss, wie etwa ob ein Element gehovert wird.
Zusammenfassung
- Wenn zwei State-Variablen sich immer gemeinsam aktualisieren, erwäge, sie zu einer zu verschmelzen.
- Wähle deine State-Variablen sorgfältig aus, um das Erstellen von "unmöglichen" Zuständen zu vermeiden.
- Strukturiere deinen State so, dass die Wahrscheinlichkeit für Fehler bei Aktualisierungen geringer wird.
- Vermeide redundanten und doppelten State, damit du ihn nicht synchron halten musst.
- Setze Props nichtinden State, es sei denn, du möchtest Updates gezielt verhindern.
- Für UI-Muster wie Auswahl, behalte eine ID oder einen Index im State, anstatt das Objekt selbst.
- Wenn das Aktualisieren von tief verschachteltem State kompliziert ist, versuche, ihn zu vereinfachen.
Try out some challenges
Challenge 1 of 4:Fix a component that’s not updating #
This Clock component receives two props: color and time. When you select a different color in the select box, the Clock component receives a different color prop from its parent component. However, for some reason, the displayed color doesn’t update. Why? Fix the problem.
