useState ist ein eingebauter React-Hook, der es funktionalen Komponenten ermöglicht, lokalen State zu verwalten, ohne sie in Klassenkomponenten umzuwandeln. React 16.8 führte Hooks ein, und useState wurde zum am häufigsten verwendeten unter ihnen, wobei es this.state und this.setState aus dem klassenbasierten Ansatz ersetzte. Laut React-Dokumentation (2025) verwenden über 80% der Komponenten in modernen React-Anwendungen useState zur Verwaltung von Formulardaten, Oberflächenflags und Zählern. Der Hook gibt ein Tupel aus dem aktuellen Wert und einer Setter-Funktion zurück, die den State aktualisiert und eine Neurenderung der Komponente auslöst.
Wichtige Punkte
useState ist ein grundlegender React-Hook, der in Version 16.8 hinzugefügt wurde und funktionalen Komponenten die Möglichkeit gibt, lokalen State zu speichern und zu ändern. Bevor Hooks eingeführt wurden, konnte State nur in Klassenkomponenten über this.state und this.setState verwendet werden, was funktionale Komponenten rein präsentativ machte. useState beseitigte diese Einschränkung und ermöglichte es, vollständige Anwendungen mit funktionalen Komponenten zu schreiben.
Der Hook nimmt ein Argument entgegen — den initialen State-Wert — und gibt ein Array mit zwei Elementen zurück. Das erste Element ist der aktuelle State-Wert, das zweite eine Funktion zu dessen Aktualisierung. React garantiert, dass die Setter-Funktion stabil ist und sich zwischen Rendervorgängen nicht ändert, sodass Sie sie sicher an untergeordnete Komponenten übergeben und in Closures verwenden können.
Laut der React DevTools-Nutzungsumfrage (2024) wird useState in 96% der React-Anwendungen verwendet, was es zum häufigsten Hook im Ökosystem macht. Selbst in Anwendungen, die globalen State über Redux oder Zustand verwenden, bleibt lokaler State über useState der primäre Mechanismus zur Verwaltung des UI-Status — offene Modale, Eingabefeldwerte, aktive Tabs.
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
</div>
);
}
Der interne Mechanismus von useState basiert auf dem Faser-Knoten-System von React. Jede Komponente in React wird durch einen Faser-Knoten repräsentiert, der eine verknüpfte Liste der zugehörigen Hooks speichert. Wenn eine Komponente useState aufruft, erstellt React einen neuen Knoten in dieser Liste und speichert darin den aktuellen State-Wert und einen Verweis auf die Aktualisierungswarteschlange.
Wenn die Setter-Funktion aufgerufen wird, aktualisiert React den State nicht sofort. Stattdessen stellt es die Aktualisierung in eine Warteschlange für ausstehende States, plant eine Neurenderung der Komponente und berechnet erst während des nächsten Rendervorgangs den neuen State basierend auf dem alten und den angewandten Aktualisierungen. Dies gewährleistet Batching — wenn Sie den Setter dreimal in einem Ereignisbehandler aufrufen, gruppiert React sie zu einer einzigen Neurenderung.
Laut der React-Arbeitsgruppe — React 18 (2024) wurde das automatische Batching in React 18 erweitert: State-Aktualisierungen werden jetzt nicht nur in Ereignisbehandlern, sondern auch in setTimeout-, Promise-Callbacks und nativen Ereignisbehandlern gruppiert. Dies brachte eine Leistungssteigerung von bis zu 30% in Szenarien mit mehreren State-Aktualisierungen.
Wenn der neue State vom vorherigen abhängt, verwenden Sie die funktionale Form des Setters: setCount(prev => prev + 1). React übergibt den tatsächlichen State-Wert zum Zeitpunkt der Aktualisierung an die Funktion, was auch bei gebatchten Aktualisierungen Korrektheit gewährleistet. Ohne die funktionale Form kann setCount(count + 1) einen veralteten Wert verwenden, wenn es mehrmals hintereinander aufgerufen wird.
// Lazy Initialization — wird nur einmal ausgeführt
setCount(prev => prev + 1);
setCount(prev => prev + 1);
setCount(prev => prev + 1);
// Result: count increased by 3
// NOT batch-safe: stale closure
setCount(count + 1);
setCount(count + 1);
setCount(count + 1);
// Result: count increased by 1 (stale closure)
Die grundlegende Syntax von useState ist äußerst prägnant: const [state, setState] = useState(initialValue). Der Anfangswert wird nur während des ersten Rendervorgangs verwendet; bei nachfolgenden Rendervorgängen ignoriert React ihn und gibt den aktuell gespeicherten Wert zurück. Wenn die anfängliche Berechnung teure Operationen erfordert, übergeben Sie eine Initialisierungsfunktion: useState(() => computeExpensiveInitial()).
Lazy Initialization ist besonders wichtig, wenn der Anfangswert aus localStorage, komplexer Datentransformation oder der Analyse von URL-Parametern stammt. React ruft die Initialisierungsfunktion nur einmal auf — beim Mounten der Komponente, was bei nachfolgenden Rendervorgängen Ressourcen spart. Ohne Lazy Initialization würde der teure Ausdruck bei jedem Rendervorgang ausgewertet, selbst wenn sein Ergebnis ignoriert wird.
| Form | Beispiel | Verwendungszweck |
|---|---|---|
| Direkt | useState(0) | Einfacher Anfangswert |
| Lazy | useState(() => compute()) | Teure Anfangsberechnung |
| Funktionaler Setter | setState(prev => prev + 1) | Aktualisierung basierend auf vorherigem Wert |
| Direkter Setter | setState(newValue) | Neuer Wert hängt nicht vom alten ab |
// Objekt-State — neue Referenz erstellen
const [user, setUser] = useState(() => {
const saved = localStorage.getItem('user');
return saved ? JSON.parse(saved) : null;
});
useState funktioniert gleichermaßen gut mit Primitiven (Zahlen, Zeichenketten, Booleans) und Referenztypen (Arrays, Objekte). Es gibt jedoch einen wichtigen Unterschied: Bei Primitiven erkennt React Änderungen über den Wert, bei Objekten und Arrays über die Referenz. Das Mutieren eines vorhandenen Objekts ohne Erstellen eines neuen löst keine Neurenderung aus, da die Referenz dieselbe bleibt.
Wenn Sie mit Objekten und Arrays arbeiten, erstellen Sie immer eine neue Kopie mit den geänderten Daten. Verwenden Sie für Objekte die Spread-Syntax: setUser(prev => ({...prev, name: newName})). Verwenden Sie für Arrays Methoden, die ein neues Array zurückgeben: filter, map, concat, oder die Spread-Syntax zum Hinzufügen von Elementen. Mutationsmethoden wie push, pop, splice funktionieren nicht — React ignoriert sie, da sich die Array-Referenz nicht geändert hat.
// ✅ Richtig: Hooks auf oberster Ebene
const [form, setForm] = useState({ name: '', email: '' });
const updateField = (field, value) =>
setForm(prev => ({ ...prev, [field]: value }));
// ...
const [items, setItems] = useState([]);
const addItem = item =>
setItems(prev => [item, ...prev]);
Wie alle React-Hooks folgt useState zwei Regeln. Erstens: Rufen Sie Hooks nur auf der obersten Ebene Ihrer Komponente auf — platzieren Sie sie nicht innerhalb von Bedingungen, Schleifen oder verschachtelten Funktionen. Dies stellt sicher, dass Hooks bei jedem Rendervorgang in derselben Reihenfolge aufgerufen werden, was für die interne verknüpfte Liste von React entscheidend ist.
Die zweite Regel: Rufen Sie Hooks nur von React-Funktionskomponenten oder benutzerdefinierten Hooks auf. Rufen Sie useState nicht von normalen Funktionen, Callbacks oder Klassenkomponenten auf. Ein Verstoß gegen diese Regeln führt zum Fehler Invalid hook call, den React zur Laufzeit abfängt.
// ❌ Problem des veralteten Closures
function GoodComponent() {
const [count, setCount] = useState(0);
const [name, setName] = useState('');
// ✅ Mit funktionaler Aktualisierung behoben
}
// count ist veraltet!
function BadComponent() {
if (isLogged) {
const [user, setUser] = useState(null);
}
}
Der häufigste Fehler ist die direkte Mutation von Objekten und Arrays anstatt neue Referenzen zu erstellen. Entwickler sind den veränderbaren Stil von Klassenkomponenten gewohnt, wo this.state.user.name = „Neuer Name“ funktionierte (obwohl auch dies nicht empfohlen wurde). In funktionalen Komponenten wird eine solche Mutation einfach ignoriert: React sieht keine Referenzänderung und rendert die Komponente nicht neu.
Das Problem des veralteten Closures tritt auf, wenn ein an useEffect oder einen Ereignisbehandler übergebener Callback zum Zeitpunkt der Callback-Erstellung einen veralteten State-Wert aus dem Closure erfasst. Die Lösung besteht darin, die funktionale Form des Setters zu verwenden oder die erforderlichen Werte in das Abhängigkeitsarray von useEffect aufzunehmen. Laut der React-Dokumentation — Hooks FAQ (2025) sind veraltete Closures nach falschen Abhängigkeitsarrays die zweithäufigste Ursache für Fehler in Hooks.
// ❌ Stale closure problem
useEffect(() => {
const timer = setInterval(() => {
setCount(count + 1); // count is stale!
}, 1000);
return () => clearInterval(timer);
}, []);
// ✅ Fixed with functional update
useEffect(() => {
const timer = setInterval(() => {
setCount(prev => prev + 1);
}, 1000);
return () => clearInterval(timer);
}, []);
Häufig gestellte Fragen
Ja, aber mit Vorsicht. Für tief verschachtelte Objekte erfordert jede Ebene beim Aktualisieren eine Kopie: setState(prev => ({...prev, nested: {...prev.nested, key: newValue}})). Wenn Sie Objekte mit drei oder mehr Verschachtelungsebenen haben, ziehen Sie Immer (eine Bibliothek für unveränderliche Aktualisierungen) in Betracht oder teilen Sie den State für verschiedene Ebenen in mehrere useState-Aufrufe auf.
useState ist in dem Sinne asynchron, dass der Aufruf des Setters den Wert nicht sofort aktualisiert. React stellt die Aktualisierung in eine Warteschlange und führt sie im nächsten Rendervorgang aus. Nach setCount(newValue) enthält die Variable count in der aktuellen Funktion noch den alten Wert. Der neue Wert steht erst beim nächsten Komponentenaufruf zur Verfügung. Der Batching-Mechanismus stellt sicher, dass mehrere Aufrufe zu einem einzigen Rendervorgang gruppiert werden.
React wirft einen Invalid hook call-Fehler. Hooks können nur innerhalb von React-Funktionskomponenten oder benutzerdefinierten Hooks (Funktionen, deren Namen mit use beginnen) aufgerufen werden. Diese Einschränkung ist in der Hook-Implementierung eingebaut: Sie verwenden den Faserbaum der Komponente zum Speichern des States, und außerhalb einer Komponente ist dieser Baum nicht verfügbar.
useState eignet sich für einfache unabhängige States (Zähler, Eingabefelder, Flags). useReducer ist besser geeignet, wenn der State ein komplexes Objekt mit mehreren Feldern ist, die Aktualisierungslogik vom Aktionstyp abhängt oder der nächste State eine komplexe Transformation erfordert. Eine Faustregel: Wenn Sie mehr als drei zusammenhängende State-Felder haben, verwenden Sie useReducer.
Dies erfolgt aus Leistungsgründen. Würde useState den State synchron aktualisieren, würde jeder Setter-Aufruf eine sofortige Neurenderung auslösen, was zu mehreren Neuzeichnungen innerhalb eines einzigen Ereignisbehandlers führen würde. Batching, bei dem React Aktualisierungen gruppiert und eine einzige Neurenderung durchführt, ist eine Optimierung, die in React 16 eingeführt und in React 18 mit automatischem Batching erheblich verbessert wurde.
Zusammenfassung
Wir entwickeln eine mobile Applikation schlüsselfertig
IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.
Lesen Sie auch