State hochziehen
Manchmal müssen zwei Komponenten denselben Zustand kennen und synchron bleiben. Die Lösung: Den State aus den Kindkomponenten entfernen und in den nächsten gemeinsamen Vorfahren hochziehen — dort zentral verwalten und nach unten weitergeben.
Das Problem: isolierter State
Abschnitt betitelt „Das Problem: isolierter State“Angenommen, wir haben eine Akkordeon-Komponente mit zwei aufklappbaren Panels. Jedes Panel verwaltet seinen isOpen-State selbst:
function Panel({ titel, children }) { const [isOpen, setIsOpen] = useState(false);
return ( <div> <button onClick={() => setIsOpen(!isOpen)}> {titel} </button> {isOpen && <div>{children}</div>} </div> );}
function Akkordeon() { return ( <div> <Panel titel="Was ist React?"> React ist eine JavaScript-Bibliothek für UIs. </Panel> <Panel titel="Was sind Komponenten?"> Komponenten sind wiederverwendbare UI-Bausteine. </Panel> </div> );}Beide Panels können unabhängig voneinander geöffnet werden — aber was, wenn immer nur ein Panel gleichzeitig offen sein soll? Dann müssen sie voneinander wissen. Das ist mit lokalem State nicht möglich: Die Panels haben keine Verbindung zueinander.
Die Lösung: State hochziehen
Abschnitt betitelt „Die Lösung: State hochziehen“Wir folgen drei Schritten:
Schritt 1: State aus den Kindkomponenten entfernen
Abschnitt betitelt „Schritt 1: State aus den Kindkomponenten entfernen“Panel bekommt isOpen und onToggle als Props — der State liegt nicht mehr in Panel selbst:
function Panel({ titel, children, isOpen, onToggle }) { return ( <div> <button onClick={onToggle}> {titel} </button> {isOpen && <div>{children}</div>} </div> );}Panel ist jetzt eine kontrollierte Komponente — sie hat keinen eigenen State mehr, sondern wird vollständig von außen gesteuert.
Schritt 2: State in den Eltern hochziehen
Abschnitt betitelt „Schritt 2: State in den Eltern hochziehen“Akkordeon übernimmt den State. Weil immer nur ein Panel offen sein soll, reicht ein einziger State-Wert: der Index des offenen Panels.
function Akkordeon() { const [offenerIndex, setOffenerIndex] = useState(0);
return ( <div> <Panel titel="Was ist React?" isOpen={offenerIndex === 0} onToggle={() => setOffenerIndex(0)} > React ist eine JavaScript-Bibliothek für UIs. </Panel> <Panel titel="Was sind Komponenten?" isOpen={offenerIndex === 1} onToggle={() => setOffenerIndex(1)} > Komponenten sind wiederverwendbare UI-Bausteine. </Panel> </div> );}Klickt der Nutzer auf Panel 1, ruft es onToggle auf — was setOffenerIndex(0) in Akkordeon auslöst. React rendert beide Panels neu: Panel 0 bekommt isOpen={true}, Panel 1 bekommt isOpen={false}.
Schritt 3 (optional): Beide schließen erlauben
Abschnitt betitelt „Schritt 3 (optional): Beide schließen erlauben“Soll auch das offene Panel wieder schließbar sein, ersetzt du den Index durch null:
function Akkordeon() { const [offenerIndex, setOffenerIndex] = useState(null);
function handleToggle(index) { setOffenerIndex(offenerIndex === index ? null : index); }
return ( <div> <Panel titel="Was ist React?" isOpen={offenerIndex === 0} onToggle={() => handleToggle(0)} > React ist eine JavaScript-Bibliothek für UIs. </Panel> <Panel titel="Was sind Komponenten?" isOpen={offenerIndex === 1} onToggle={() => handleToggle(1)} > Komponenten sind wiederverwendbare UI-Bausteine. </Panel> </div> );}Das Muster: Daten runter, Events hoch
Abschnitt betitelt „Das Muster: Daten runter, Events hoch“State hochziehen folgt immer demselben Schema:
Akkordeon ←── hält State (offenerIndex) │ ├── isOpen={...} ──▶ Panel 0 │ onToggle={...} ◀── ruft onToggle() auf │ └── isOpen={...} ──▶ Panel 1 onToggle={...} ◀── ruft onToggle() auf- Daten fließen nach unten — als Props:
isOpen - Events fließen nach oben — als Callbacks:
onToggle - Der State liegt zentral — eine Quelle der Wahrheit, kein duplizierter Zustand
Kontrolliert vs. unkontrolliert
Abschnitt betitelt „Kontrolliert vs. unkontrolliert“Ein Begriff, der hier auftaucht: kontrolliert und unkontrolliert — du kennst ihn schon von Formular-Inputs, aber er gilt genauso für eigene Komponenten.
| Unkontrolliert | Kontrolliert | |
|---|---|---|
| State liegt in | der Komponente selbst | dem Elternelement |
| Gesteuert durch | lokales useState | Props von außen |
| Flexibilität | weniger — schwerere Koordination | mehr — Elternelement bestimmt alles |
| Beispiel | Panel mit eigenem isOpen | Panel mit isOpen-Prop |
Unkontrollierte Komponenten sind einfacher zu verwenden (weniger Props), aber schwerer zu koordinieren. Kontrollierte Komponenten erfordern mehr Konfiguration, sind aber vollständig von außen steuerbar.
Wo liegt der richtige Ort für State?
Abschnitt betitelt „Wo liegt der richtige Ort für State?“Als Faustregel: State gehört zum niedrigsten gemeinsamen Vorfahren aller Komponenten, die ihn brauchen.
- Braucht nur eine Komponente den State? → Lokal in ihr.
- Brauchen mehrere Geschwister-Komponenten denselben State? → Zum gemeinsamen Elternelement hochziehen.
- Brauchen viele tief verschachtelte Komponenten denselben State? → Dann lohnt sich ein Blick auf Context (kommt später).