useEffect ist ein React-Hook, mit dem Sie Nebeneffekte in funktionalen Komponenten ausführen können und der die Lebenszyklusmethoden von Klassenkomponenten ersetzt: componentDidMount, componentDidUpdate und componentWillUnmount. Laut React Documentation (2025) wird useEffect ausgeführt, nachdem React Änderungen am DOM vorgenommen hat, was den Zugriff auf den aktuellen DOM-Baum gewährleistet. Der Hook akzeptiert eine Effektfunktion und ein optionales Abhängigkeitsarray, das die Ausführungshäufigkeit steuert.
Wichtige Erkenntnisse
useEffect ist ein in React 16.8 eingeführter Hook zur Ausführung von Nebeneffekten in funktionalen Komponenten. Zu den Nebeneffekten gehören Operationen, die nicht direkt mit der UI-Rendering zusammenhängen: HTTP-Anfragen an APIs, Ereignisabonnements, Arbeit mit Timern, DOM-Manipulationen, Protokollierung und Integration mit Drittanbieterbibliotheken.
Vor Hooks mussten all diese Operationen in den Lebenszyklusmethoden von Klassenkomponenten platziert werden: componentDidMount für die Initialisierung, componentDidUpdate für Reaktion auf Prop-Änderungen, componentWillUnmount für die Bereinigung. useEffect vereinte alle drei Szenarien in einer einzigen API, bei der das Abhängigkeitsarray bestimmt, wann der Effekt ausgeführt werden soll. Dies vereinfachte die Logik und reduzierte Code-Duplizierung, insbesondere bei Abonnementszenarien.
Laut React DevTools Usage Survey (2024) ist useEffect nach useState der zweitbeliebteste Hook und wird in 89% der React-Anwendungen verwendet. Die meisten Entwickler nutzen ihn zum Abrufen von Daten, zum Synchronisieren mit externen Systemen und zur Verwaltung von DOM-Ereignisabonnements.
import { useEffect } from 'react';
function UserProfile({ userId }) {
useEffect(() => {
fetch(`/api/users/${userId}`)
.then(res => res.json())
.then(data => setUser(data));
}, [userId]);
}
useEffect führt die übergebene Effektfunktion aus, nachdem React das Rendering abgeschlossen und das DOM aktualisiert hat. Dies ist ein wesentlicher Unterschied zu Berechnungen zur Renderzeit: Der Effekt blockiert das Rendering nicht, was für die UX-Leistung entscheidend ist. Wenn Effekte synchron ausgeführt würden, sähen Benutzer während des Datenladens eine eingefrorene Oberfläche.
Der Lebenszyklus eines typischen Effekts besteht aus drei Phasen. Beim Mounten der Komponente führt React den Effekt aus. Bei jedem Update, wenn sich mindestens eine Abhängigkeit im Array geändert hat, führt React zuerst die Bereinigungsfunktion des vorherigen Effekts aus, dann den neuen Effekt. Beim Unmounten der Komponente wird nur die Bereinigungsfunktion ausgeführt.
Laut React Team — useEffect RFC (2024) verwendet die interne Implementierung von useEffect eine Nebeneffekt-Warteschlange im Fiber-Baum. Nach dem Bestätigen der Änderungen (Commit-Phase) durchläuft React diese Warteschlange und ruft die Effektfunktionen in der Reihenfolge auf, in der sie in der Komponente deklariert wurden. Jeder Fiber-Knoten speichert einen Verweis auf den vorherigen Effekt für korrekte Bereinigung und Neustart.
| Phase | React-Aktion | Wann wird ausgeführt |
|---|---|---|
| Mounten | Effektfunktion aufrufen | Nach dem ersten Rendern |
| Update | Bereinigung → Effekt | Bei Änderung der Abhängigkeiten |
| Unmounten | Nur Bereinigung | Beim Entfernen der Komponente |
Das Abhängigkeitsarray — das zweite Argument von useEffect — bestimmt, wann der Effekt neu gestartet werden soll. React vergleicht jeden Wert im Array mit dem vorherigen Rendering mittels Object.is. Wenn sich mindestens ein Wert geändert hat, wird der Effekt erneut ausgeführt. Wenn das Array leer ist ([]), wird der Effekt nur einmal nach dem Mounten ausgeführt.
Die Wahl der richtigen Abhängigkeiten ist der schwierigste Teil der Arbeit mit useEffect. Das Array muss alle Variablen und Funktionen enthalten, die innerhalb des Effekts verwendet werden und sich zwischen Renderings ändern können. Das Weglassen einer Abhängigkeit führt zu stale closures — der Effekt sieht einen veralteten Wert aus dem vorherigen Rendering. Das Einfügen unnötiger Abhängigkeiten führt zu übermäßigen Neustarts und potenziellen Fehlern.
// Abhängigkeiten steuern, wann der Effekt neu ausgeführt wird
useEffect(() => {
document.title = `User: ${user.name}`;
}, [user.name]); // nur neu ausführen, wenn sich user.name ändert
// eslint-disable-next-line react-hooks/exhaustive-deps
// Wenn Sie eine Abhängigkeit weglassen, erhalten Sie veraltete Daten
React bietet eslint-plugin-react-hooks mit der Regel exhaustive-deps, die automatisch die Vollständigkeit des Abhängigkeitsarrays prüft. Laut Meta Engineering Blog (2024) reduziert die Aktivierung dieses Plugins hook-bezogene Fehler um 72%. Es wird empfohlen, alle exhaustive-deps-Warnungen zu beheben, anstatt sie mit einem Kommentar zu unterdrücken, außer in seltenen Fällen mit benutzerdefinierter Logik.
Wenn Sie das Abhängigkeitsarray ganz weglassen, wird useEffect nach jedem Rendering ausgeführt. Dies kann für die DOM-Synchronisierung oder Protokollierung nützlich sein, ist aber meistens ein Fehler: Der Effekt wird zu häufig ausgeführt, was zu Leistungseinbußen führt. In den meisten Fällen sollten Sie ein leeres Array (einmal beim Mounten) oder ein Array mit bestimmten Props/State übergeben.
Ein leeres Array ([]) bedeutet, dass der Effekt von keinen Werten abhängt und strikt einmal ausgeführt wird. Dies entspricht componentDidMount in Klassenkomponenten. Beachten Sie jedoch: Wenn der Effekt Props oder State verwendet, die nicht im Abhängigkeitsarray aufgeführt sind, verwendet der Effekt deren Anfangswerte und sieht niemals Aktualisierungen. Dies wird als stale capture bezeichnet und ist häufig eine Quelle schwer zu findender Fehler.
| Abhängigkeitsarray | Verhalten | Klassen-Äquivalent |
|---|---|---|
| Kein Argument | Nach jedem Rendering | componentDidUpdate |
| [] | Einmal beim Mounten | componentDidMount |
| [a, b] | Bei Änderung von a oder b | ComponentWillReceiveProps-Analogon |
| return cleanup | Unmounten verwalten | componentWillUnmount |
Die Bereinigungsfunktion ist eine Funktion, die useEffect aus seinem Callback zurückgeben kann. React ruft sie beim Unmounten der Komponente und vor dem erneuten Ausführen des Effekts bei Änderung der Abhängigkeiten auf. Die Bereinigung ist notwendig, um Abonnements, Timer, Anfragen und alle Ressourcen zu kündigen, die freigegeben werden müssen.
Ein typisches Beispiel ist ein WebSocket-Abonnement. Beim Mounten wird eine Verbindung erstellt; bei Aktualisierung der Abhängigkeiten wird sie neu erstellt (Bereinigung schließt die alte, der Effekt öffnet eine neue); beim Unmounten wird sie geschlossen. Ohne Bereinigung würde jedes erneute Mounten der Komponente eine neue WebSocket-Verbindung erstellen, was zu Speicherlecks und mehreren Verbindungen führt.
useEffect(() => {
const socket = new WebSocket('wss://api.example.com');
socket.onmessage = event => setData(event.data);
// Bereinigungsfunktion — wird beim Unmounten und vor der erneuten Ausführung ausgeführt
return () => {
socket.close();
};
}, []);
Laut React Documentation (2025) ist AbortController der moderne Ansatz zum Abbrechen von Fetch-Anfragen in der Bereinigung. Wenn der Effekt eine HTTP-Anfrage stellt und die Komponente vor deren Abschluss unmountet, läuft die Anfrage weiter und setState nach dem Unmounten verursacht einen Fehler. Erstellen Sie einen AbortController innerhalb des Effekts und rufen Sie controller.abort() in der Bereinigung auf, um die Anfrage abzubrechen.
Der häufigste Fehler ist das Weglassen von Abhängigkeiten. Beispielsweise verwendet der Effekt die Prop userId, aber das Abhängigkeitsarray ist leer. Infolgedessen wird der Effekt einmal mit dem anfänglichen userId-Wert ausgeführt und reagiert nie auf dessen Änderungen. Der Entwickler sieht, dass die Komponente eine neue userId erhält, aber die Daten werden nicht aktualisiert. eslint-plugin-react-hooks mit der Regel exhaustive-deps erkennt solche Fehler automatisch.
// ❌ Race Condition — keine Stornierung
useEffect(() => {
fetch(`/api/user/${userId}`).then(res => setUser(res));
}, [userId]);
// ✅ Mit AbortController behoben
useEffect(() => {
const controller = new AbortController();
fetch(`/api/user/${userId}`, { signal: controller.signal })
.then(res => setUser(res));
return () => controller.abort();
}, [userId]);
Um das Problem der Endlosschleife zu lösen, vermeiden Sie es, Logik in useEffect zu platzieren, die den Zustand basierend auf dem vorherigen Zustand aktualisiert. Verwenden Sie die funktionale Form von setState oder verschieben Sie Berechnungen außerhalb des Effekts. Wenn der Effekt Storage- oder Browser-Ereignisse abonniert, stellen Sie sicher, dass die Listener-Instanz einmal erstellt wird, nicht bei jedem Rendern.
Häufig gestellte Fragen
Direkt — nein, weil useEffect eine synchrone Funktion oder undefined als Rückgabe erwartet. Wenn der Callback als async deklariert wird, gibt er ein Promise zurück, das React ignoriert, und der Bereinigungsmechanismus funktioniert nicht mehr. Lösung: Rufen Sie eine async-Funktion innerhalb des Effekts auf: useEffect(() => { async function load() { ... }; load(); }, []).
Es gibt kein Limit. React empfiehlt, nicht zusammenhängende Logik in separate useEffect-Hooks aufzuteilen, selbst wenn sie dasselbe Abhängigkeitsarray haben. Jeder Effekt sollte für eine klar definierte Nebenaufgabe verantwortlich sein: einer für Abonnements, einer für Daten laden, einer für die Synchronisierung des Tab-Titels. Dies vereinfacht das Verständnis und die Fehlersuche.
Im React Strict Mode (nur Entwicklungsmodus) werden alle Effekte gemountet, unmountet und erneut gemountet. Dies ist eine Funktion, kein Fehler — React überprüft, ob die Bereinigung korrekt funktioniert. Wenn der Effekt nach dem Unmounten und erneuten Mounten falsch reagiert (z. B. doppelte Abonnements), ist Ihre Bereinigung unvollständig. In der Produktion wird der Effekt einmal ausgeführt.
Verwenden Sie AbortController. Erstellen Sie einen Controller innerhalb des Effekts, übergeben Sie controller.signal an fetch und rufen Sie controller.abort() in der Bereinigung auf. Wenn die Komponente vor Abschluss der Anfrage unmountet, wird fetch abgebrochen und setState wird nicht aufgerufen. Dies verhindert Race Conditions und den Fehler „Can‘t perform a React state update on an unmounted component“.
useEffect wird ausnahmslos nach jedem Rendering ausgeführt. Das bedeutet, dass jedes setState innerhalb des Effekts ein neues Rendering → neuen Effekt → Endlosschleife verursacht. In der Praxis ist ein Effekt ohne Abhängigkeitsarray fast immer ein Fehler. Ausnahmen sind Protokollierung oder Synchronisierung mit einem externen System, bei dem jedes Rendering eine Synchronisierung erfordert.
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