Zwei der wichtigsten Konzepte in React – State und Props – werden gerne verwechselt. Beide halten Daten, beide lösen Re-Renders aus, beide werden in Komponenten genutzt. Trotzdem haben sie unterschiedliche Aufgaben und unterschiedliche Eigenschaften. Dieser Artikel erklärt den Unterschied, zeigt typische Verwechslungen und gibt klare Regeln, wann Daten in den State gehören und wann sie als Prop gereicht werden sollten.
Die Kernunterschiede in einem Bild
| Eigenschaft | State | Props |
|---|---|---|
| Wer besitzt die Daten? | Die Komponente selbst | Die Eltern-Komponente |
| Wer darf sie ändern? | Nur die besitzende Komponente | Niemand (read-only innerhalb Kind) |
| Reicht weiter nach unten? | Optional, über Props | Ja, von Eltern zu Kind |
| Initialisierung | useState(initialValue) | Beim JSX-Aufruf gesetzt |
| Anwendung | Veränderliche, lokale Werte | Daten, die von außen kommen |
| Auslöser für Re-Render | setState-Aufruf | Geänderte Prop vom Eltern-Render |
Kurz: Props kommen von außen rein, State entsteht innen.
Beispiel-Komponente mit beidem
import { useState } from 'react';
function Greeting({ name }) {
const [greeted, setGreeted] = useState(false);
return (
<div>
<h1>Hallo, {name}!</h1>
{!greeted && (
<button onClick={() => setGreeted(true)}>
Begrüßung bestätigen
</button>
)}
{greeted && <p>Schön, dich zu sehen.</p>}
</div>
);
}nameist eine Prop – kommt von außen, wird im Kind nicht verändert.greetedist State – gehört zur Komponente, wird per Klick verändert.
Props sind read-only
Eine Komponente darf ihre Props nicht direkt verändern. Das ist eine harte Regel von React – Verstöße führen zu schwer auffindbaren Bugs, weil die Eltern-Komponente die Daten weiter besitzt und in einem späteren Render möglicherweise einen anderen Wert erwartet.
function Counter({ count }) {
count++; // − Prop wird mutiert
return <p>{count}</p>;
}Soll der Wert sich ändern können, muss er in den State (entweder lokal oder im Eltern-Component, der die Prop reicht). Mehr dazu unter State Lifting.
Drei Faustregeln zur Entscheidung
Wenn unklar ist, ob ein Wert State oder Prop sein soll, frage in dieser Reihenfolge:
- Bleibt der Wert über die Zeit gleich? -> Konstante. Weder State noch Prop, sondern eine normale Variable oder Konstante.
- Bekommt die Komponente den Wert von außen? -> Prop.
- Kann sich der Wert über die Zeit ändern, und keine andere Komponente besitzt ihn? -> State.
Wenn der Wert sich aus anderen Werten berechnen lässt, gehört er weder in State noch in Props – er wird beim Rendern abgeleitet:
function Cart({ items }) {
const total = items.reduce((sum, item) => sum + item.price, 0);
return <p>Gesamt: {total} €</p>;
}total darf weder State noch Prop sein – es ist eine reine Funktion von items.
State und Props zusammen
Häufig leitet ein Eltern-Komponente seinen State an Kinder weiter. Aus Sicht des Eltern ist es State, aus Sicht des Kindes ist es eine Prop. Das ist der Kern des einseitigen Datenflusses:
function Counter() {
const [count, setCount] = useState(0); // State im Parent
return (
<div>
<Display value={count} />
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
);
}
function Display({ value }) {
// Aus Sicht von Display ist value eine Prop
return <p>{value}</p>;
}Display weiß nicht, woher der Wert kommt – ob aus State, aus einem Context oder aus einem Server-Request. Genau das macht es wiederverwendbar.
Anti-Pattern: Prop in State spiegeln
Ein häufiger Fehler: Eine Prop wird beim Mounten in einen State kopiert, um sie „bearbeitbar" zu machen.
function Form({ initialName }) {
const [name, setName] = useState(initialName);
// Problem: Wenn sich initialName ändert, bleibt name auf altem Wert.
return <input value={name} onChange={(e) => setName(e.target.value)} />;
}Das funktioniert für den ersten Render – aber wenn der Eltern-Komponent eine neue initialName-Prop liefert, bleibt der State auf dem alten Wert hängen. Bessere Optionen:
- Prop direkt verwenden, falls keine Bearbeitung nötig ist.
- Den State im Eltern-Komponent halten und Setter als Prop reichen.
- Per
key-Prop den State bewusst zurücksetzen, wenn die Identität wechselt.
// Wenn userId wechselt, wird der gesamte State von Form weggeworfen
<Form key={userId} initialName={userName} />Was passiert beim Re-Render?
- State-Update (
setX(...)) führt dazu, dass die Komponente und ihre Kinder neu gerendert werden. - Prop-Änderung führt dazu, dass die empfangende Komponente neu gerendert wird.
In beiden Fällen baut React den virtuellen Baum neu auf und vergleicht ihn mit dem alten. Das heißt: Sobald State irgendwo oben wechselt, rendern alle abhängigen Komponenten – das ist das normale, gewünschte Verhalten. Performance-Stellschrauben dafür: React.memo, useMemo, useCallback.
Interessantes
State ist intern, Props sind extern — eine Sache der Perspektive.
Was in Komponente A State ist, kann in Komponente B als Prop ankommen — wenn B ein Kind von A ist und A den Wert weiterreicht. Daher: State und Props sind nicht zwei Arten von Werten, sondern zwei Rollen desselben Werts.
Props sind read-only — eine harte Regel.
Wer in der Kind-Komponente props.value = 5 schreibt, hat einen Bug. React erwartet, dass Props immutable sind. Wenn das Kind den Wert ändern können soll, gehört ein Callback-Prop mit (z.B. onChange), den das Kind aufruft.
State lebt im React-internen Speicher, nicht in der Komponenten-Funktion.
Bei jedem Render läuft die Komponenten-Funktion neu — aber useState liest den Wert aus dem internen Speicher, nicht aus der Funktion. Deshalb überlebt State zwischen Renders, obwohl die Funktion neu ausgeführt wird.
Props können sich zwischen Renders ändern — State im Initializer nicht.
Wer initialen State aus Props ableitet (useState(props.value)), bekommt den Wert NUR beim ersten Mount. Ändern sich Props später, hat das keinen Einfluss. Lösung: useEffect mit Props in Dependencies, oder key-Prop für Re-Mount.
Doppelter State ist ein Anti-Pattern — Single Source of Truth.
Wenn dieselbe Information in zwei States/Props existiert, kann sie auseinanderlaufen. Faustregel: Daten an EINER Stelle halten, von dort an alle Konsumenten propagieren — entweder via Props oder Context.
State Lifting ist die Antwort auf 'wo gehört der State hin?'
Wenn zwei Geschwister-Komponenten denselben Wert brauchen: in den gemeinsamen Eltern lifen. Wenn drei tief verschachtelte Komponenten denselben Wert brauchen: noch höher lifen, oder Context nutzen.
Boolean-Props mit isXyz, hasXyz, canXyz benennen.
Naming-Konvention: isOpen, hasError, canSubmit. Macht beim Lesen sofort klar, dass es eine boolean Prop ist. Setter analog: setIsOpen.
Bei React.memo: Props-Vergleich per Reference-Identity.
React.memo(Child) rendert nur neu, wenn sich Props per Object.is-Vergleich ändern. Daher: bei Objekt/Array/Funktion-Props auf Reference-Stabilität achten — sonst memo ist wirkungslos.