State mit Objekten und Arrays
Wenn der State ein Objekt oder ein Array ist, reicht es nicht, einfach eine Setter-Funktion aufzurufen. Du musst verstehen, wie React Änderungen erkennt — und warum Immutability dabei die entscheidende Rolle spielt.
Das Grundprinzip: Immutability
Abschnitt betitelt „Das Grundprinzip: Immutability“React erkennt eine State-Änderung nicht dadurch, dass du Werte veränderst — sondern dadurch, dass du neue Werte übergibst. React vergleicht beim Setter-Aufruf intern: „Ist das der gleiche Wert wie vorher?” Bei primitiven Werten (string, number, boolean) ist das einfach. Bei Objekten und Arrays vergleicht React die Referenz — also ob es dasselbe Objekt im Speicher ist.
Das bedeutet: Wenn du ein Objekt im State direkt mutierst und dann denselben Verweis übergibst, sieht React keinen Unterschied:
// ❌ Falsch — React bemerkt die Änderung nichtconst [person, setPerson] = useState({ name: "Dan", alter: 30 });
function handleClick() { person.alter = 31; // das Objekt wird mutiert... setPerson(person); // ...aber person ist noch die gleiche Referenz}Statt das bestehende Objekt zu verändern, erstellst du immer ein neues Objekt und übergibst es:
// ✅ Richtig — neues Objekt, neue Referenz, React rendert neufunction handleClick() { setPerson({ name: "Dan", alter: 31 });}Behandle State-Objekte so, als wären sie eingefroren (read-only). Du liest sie, aber du veränderst sie nie — du ersetzt sie.
State mit Objekten
Abschnitt betitelt „State mit Objekten“Ein Feld aktualisieren
Abschnitt betitelt „Ein Feld aktualisieren“Wenn du nur ein Feld eines Objekts ändern willst, kopierst du das bestehende Objekt mit dem Spread-Operator und überschreibst nur das eine Feld:
const [person, setPerson] = useState({ name: "Dan", email: "dan@example.com", alter: 30,});
function handleNameChange(event) { setPerson({ ...person, // alle bestehenden Felder kopieren name: event.target.value, // dieses Feld überschreiben });}...person kopiert alle Felder des Objekts in das neue Objekt. Felder, die danach angegeben werden, überschreiben das Kopierte.
Formulare mit dynamischen Feldnamen
Abschnitt betitelt „Formulare mit dynamischen Feldnamen“Wenn du ein Formular mit mehreren Feldern verwaltest, kannst du einen einzigen Handler für alle Felder schreiben — mit dem berechneten Eigenschaftsnamen [event.target.name]:
function AnmeldeFormular() { const [formular, setFormular] = useState({ name: "", email: "", nachricht: "", });
function handleChange(event) { setFormular({ ...formular, [event.target.name]: event.target.value, }); }
return ( <form> <input name="name" value={formular.name} onChange={handleChange} /> <input name="email" value={formular.email} onChange={handleChange} /> <textarea name="nachricht" value={formular.nachricht} onChange={handleChange} /> </form> );}[event.target.name] ist ein berechneter Eigenschaftsname: Der Wert des name-Attributs des Inputs wird als Schlüssel im Objekt verwendet.
Verschachtelte Objekte
Abschnitt betitelt „Verschachtelte Objekte“Spread ist flach — er kopiert nur die oberste Ebene. Bei verschachtelten Objekten musst du auf jeder Ebene spreaden:
const [person, setPerson] = useState({ name: "Dan", adresse: { stadt: "Berlin", land: "Deutschland", },});
function handleStadtChange(event) { setPerson({ ...person, adresse: { ...person.adresse, // die innere Ebene kopieren stadt: event.target.value, // dann überschreiben }, });}Bei tiefer Verschachtelung wird das schnell unübersichtlich. In diesem Fall lohnt sich ein Blick auf Immer — eine Bibliothek, die Immutability hinter den Kulissen übernimmt und mutierenden Schreibstil erlaubt.
State mit Arrays
Abschnitt betitelt „State mit Arrays“Arrays im State folgen demselben Prinzip: Du veränderst das bestehende Array nie — du erstellst immer ein neues.
Viele der gewohnten Array-Methoden mutieren das Original (push, pop, splice, sort, …). Für State-Updates verwendest du stattdessen Methoden, die ein neues Array zurückgeben.
Übersicht: Welche Methoden sind sicher?
Abschnitt betitelt „Übersicht: Welche Methoden sind sicher?“| Operation | ❌ Vermeiden (mutiert) | ✅ Verwenden (neues Array) |
|---|---|---|
| Element hinten anfügen | push(el) | [...arr, el] |
| Element vorne anfügen | unshift(el) | [el, ...arr] |
| Element an Position einfügen | splice(i, 0, el) | [...arr.slice(0, i), el, ...arr.slice(i)] |
| Element entfernen (nach Wert) | splice(i, 1) | arr.filter(el => el !== ziel) |
| Element entfernen (nach Index) | splice(i, 1) | arr.filter((_, i) => i !== index) |
| Element aktualisieren | arr[i] = neuerWert | arr.map((el, i) => i === index ? neuerWert : el) |
| Objekt in Array aktualisieren | direktes Feld setzen | arr.map(el => el.id === id ? { ...el, feld: wert } : el) |
| Array umkehren | reverse() | [...arr].reverse() |
| Array sortieren | sort() | [...arr].sort() |
| Teilbereich kopieren | splice() | arr.slice(start, ende) |
Elemente hinzufügen
Abschnitt betitelt „Elemente hinzufügen“const [aufgaben, setAufgaben] = useState(["Einkaufen", "Kochen"]);
// Hinten anfügenfunction hinzufuegen(neueAufgabe) { setAufgaben([...aufgaben, neueAufgabe]);}
// Vorne anfügenfunction vornAnfuegen(neueAufgabe) { setAufgaben([neueAufgabe, ...aufgaben]);}Elemente entfernen
Abschnitt betitelt „Elemente entfernen“const [aufgaben, setAufgaben] = useState(["Einkaufen", "Kochen", "Sport"]);
// Nach Wert entfernenfunction entfernen(aufgabe) { setAufgaben(aufgaben.filter(a => a !== aufgabe));}
// Nach Index entfernenfunction entfernenNachIndex(index) { setAufgaben(aufgaben.filter((_, i) => i !== index));}Elemente aktualisieren
Abschnitt betitelt „Elemente aktualisieren“const [zaehler, setZaehler] = useState([0, 0, 0]);
function erhoehen(index) { setZaehler(zaehler.map((wert, i) => i === index ? wert + 1 : wert));}Objekte in Arrays aktualisieren
Abschnitt betitelt „Objekte in Arrays aktualisieren“Beim Kopieren eines Arrays mit Spread oder map werden nur die Referenzen auf die enthaltenen Objekte kopiert — die Objekte selbst bleiben dieselben. Du musst also auch das betroffene Objekt neu erstellen:
const [produkte, setProdukte] = useState([ { id: 1, name: "Apfel", preis: 0.5 }, { id: 2, name: "Brot", preis: 1.8 }, { id: 3, name: "Milch", preis: 1.2 },]);
function preisAktualisieren(id, neuerPreis) { setProdukte(produkte.map(produkt => produkt.id === id ? { ...produkt, preis: neuerPreis } // neues Objekt mit geändertem Feld : produkt // unverändertes Objekt ));}Element an bestimmter Position einfügen
Abschnitt betitelt „Element an bestimmter Position einfügen“function einfuegenNach(index, neuesElement) { setAufgaben([ ...aufgaben.slice(0, index + 1), neuesElement, ...aufgaben.slice(index + 1), ]);}Array sortieren und umkehren
Abschnitt betitelt „Array sortieren und umkehren“sort() und reverse() mutieren das Original. Erstelle zuerst eine Kopie:
function sortieren() { const sortiert = [...aufgaben].sort(); setAufgaben(sortiert);}
function umkehren() { setAufgaben([...aufgaben].reverse());}Zusammenfassung
Abschnitt betitelt „Zusammenfassung“| Konzept | Beschreibung |
|---|---|
| Immutability | State nie direkt ändern — immer neue Objekte/Arrays erstellen |
| Objekt aktualisieren | { ...obj, geaendertesfeld: neuerWert } |
| Verschachtelte Objekte | Auf jeder Ebene spreaden: { ...obj, nested: { ...obj.nested, feld: wert } } |
| Element anfügen | [...arr, neuesElement] statt push |
| Element entfernen | arr.filter(...) statt splice |
| Element aktualisieren | arr.map(...) statt direkter Zuweisung |
| Sortieren/Umkehren | Erst kopieren [...arr], dann sort() / reverse() |