Zum Inhalt springen

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.

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.

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.

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}.

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>
);
}

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

Ein Begriff, der hier auftaucht: kontrolliert und unkontrolliert — du kennst ihn schon von Formular-Inputs, aber er gilt genauso für eigene Komponenten.

UnkontrolliertKontrolliert
State liegt inder Komponente selbstdem Elternelement
Gesteuert durchlokales useStateProps von außen
Flexibilitätweniger — schwerere Koordinationmehr — Elternelement bestimmt alles
BeispielPanel mit eigenem isOpenPanel 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.

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).