Der FehlerMaximale Aktualisierungstiefe überschritten. Dies kann passieren, wenn eine Komponente wiederholt setState innerhalb von ComponentWillUpdate oder ComponentDidUpdateaufruft (oder in einem useEffect) bedeutet, dass Ihre Komponente in einer Endlos-Renderschleife steckt. Hier ist jede Ursache und ihre Lösung.
📋 Table of Contents
- Warum das passiert
- Ursache 1: Aufruf von setState direkt in Render/Body
- Ursache 2: Eine Funktion aufrufen, anstatt sie zu übergeben
- Ursache 3: useEffect aktualisiert seine eigene Abhängigkeit
- Ursache 4: Objekt/Array/Funktion in useEffect-Abhängigkeiten
- Ursache 5: Festlegen des Status in einem Ereignishandler, der beim Rendern ausgelöst wird
- So debuggen Sie die Schleife
- Die goldenen Regeln
- Häufig gestellte Fragen
- Fazit
Warum das passiert
Reagieren Sie erneut, wenn sich der Status ändert. Wenn eine Statusaktualisierung ein Rendern auslöst, das eine weitere Statusaktualisierung auslöst, erhalten Sie eine Endlosschleife. React erkennt dies und meldet „Maximale Aktualisierungstiefe überschritten“, um zu verhindern, dass Ihr Browser einfriert.
Ursache 1: Aufruf von setState direkt in Render/Body
// 🐛 setState called during render → triggers re-render → loops forever
function Counter() {
const [count, setCount] = useState(0);
setCount(count + 1); // ❌ runs on every render → infinite loop
return <div>{count}</div>;
}
// ✅ Only update state in event handlers or effects
function Counter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>{count}</button>;
}
Ursache 2: Eine Funktion aufrufen, anstatt sie zu übergeben
// 🐛 onClick={handleClick()} CALLS handleClick during render
<button onClick={handleClick()}>Click</button>
// If handleClick calls setState, it loops on every render
// ✅ Pass the function reference, don't call it
<button onClick={handleClick}>Click</button>
// ✅ Or wrap in an arrow function if you need to pass arguments
<button onClick={() => handleClick(id)}>Click</button>
Ursache 3: useEffect aktualisiert seine eigene Abhängigkeit
// 🐛 Effect sets state that's in its dependency array
function Component() {
const [data, setData] = useState([]);
useEffect(() => {
setData([...data, newItem]); // ❌ changes data → effect re-runs → loop
}, [data]); // depends on data, which the effect changes
}
// ✅ Use a functional update and remove data from deps
function Component() {
const [data, setData] = useState([]);
useEffect(() => {
setData(prev => [...prev, newItem]); // functional update
}, []); // runs once — no dependency on data
}
Ursache 4: Objekt/Array/Funktion in useEffect-Abhängigkeiten
// 🐛 New object reference every render → effect always re-runs
function Component({ userId }) {
const options = { id: userId }; // NEW object each render
useEffect(() => {
fetchData(options);
setState(...);
}, [options]); // options is "new" every render → infinite loop
}
// ✅ Depend on the primitive value, or memoize the object
function Component({ userId }) {
useEffect(() => {
fetchData({ id: userId });
setState(...);
}, [userId]); // primitive — stable across renders
// OR memoize:
const options = useMemo(() => ({ id: userId }), [userId]);
}
Ursache 5: Festlegen des Status in einem Ereignishandler, der beim Rendern ausgelöst wird
// 🐛 onChange fires and setState causes re-render, which re-triggers...
// often from passing changing props to controlled components incorrectly
// 🐛 Also common: updating parent state that re-renders and resets child
function Parent() {
const [value, setValue] = useState('');
return <Child onValueChange={setValue(newValue)} />; // ❌ called in render
}
// ✅ Pass the setter reference
function Parent() {
const [value, setValue] = useState('');
return <Child onValueChange={setValue} />; // pass reference
}
So debuggen Sie die Schleife
// 1. Add a log to see how often the component renders
function Component() {
console.log('render'); // if this floods the console, you have a loop
// ...
}
// 2. Log inside the effect to find the culprit
useEffect(() => {
console.log('effect running');
// ...
}, [dep1, dep2]);
// 3. Log each dependency to see which one keeps changing
useEffect(() => {
console.log('dep1:', dep1, 'dep2:', dep2);
}, [dep1, dep2]);
// 4. The React DevTools Profiler highlights components re-rendering rapidly
Die goldenen Regeln
- Rufen Sie setState niemals direkt im Komponentenkörperauf – nur in Ereignishandlern, Effekten oder Rückrufen
- Übergeben Sie Funktionsverweise an Ereignishandler, nennen Sie sie nicht (
onClick={fn}nichtonClick={fn()}) - Verwenden Sie funktionale Updates (
setState(prev => ...)), wenn der neue Status vom alten Status abhängt - Abhängig von Grundelementen in useEffect oder speichern Sie Objekte/Funktionen mit useMemo/useCallback
- Fügen Sie den Status nicht in die Deps eines useEffects ein, wenn der Effekt diesen Status aktualisiert
Häufig gestellte Fragen
F: Was ist der Unterschied zwischen diesem und „Zu viele erneute Renderings“?
A: Sie hängen eng zusammen – beide sind Endlos-Renderschleifen. „Zu viele erneute Renderings“ bedeutet normalerweise, dass setState direkt während des Renderns aufgerufen wird; „Maximale Aktualisierungstiefe überschritten“ weist häufig auf eine useEffect- oder Lebenszyklusmethode hin, die die Schleife verursacht. Die Korrekturen überschneiden sich.
F: Warum führt die direkte Übergabe von setState zu einer Schleife?
A: Wenn SieonClick={setState(x)}schreiben , das setState während des Renderns aufruft (nicht beim Klicken). setState löst ein erneutes Rendern aus, das es erneut aufruft – Endlosschleife. PassonClick={() => setState(x)} stattdessen.
F: Wie aktualisiere ich den Status basierend auf dem vorherigen Status sicher?
A: Verwenden Sie ein Funktionsupdate:setCount(prev => prev + 1). Dies erfordert keincount in Ihrem Abhängigkeitsarray, um eine häufige Schleifenursache zu vermeiden.
F: Meine Objektabhängigkeit verursacht ständig Schleifen. Was mache ich?
A: Objekte und Arrays erhalten bei jedem Rendern neue Referenzen. Entweder hängen Sie von den darin enthaltenen Grundwerten ab ([obj.id]nicht[obj]) oder merken Sie sich das Objekt mituseMemo(() => obj, [deps]).
F: Kann ESLint diese abfangen?
A: Daseslint-plugin-react-hooks Die Regel „executive-deps“ weist auf viele Abhängigkeitsprobleme hin. Es fängt nicht jede Schleife ab, verhindert aber die häufigsten Fehler bei useEffect-Abhängigkeiten. Installieren und aktivieren Sie es.
Fazit
„Maximale Aktualisierungstiefe überschritten“ ist immer eine endlose Renderschleife. Die häufigsten Ursachen: Aufruf von setState direkt im Render-Body, Aufruf (anstatt Übergabe) einer Funktion in einem Event-Handler, ein useEffect, der seine eigene Abhängigkeit aktualisiert, oder instabile Objekt-/Funktionsabhängigkeiten. Die Korrekturen:Aktualisieren Sie nur den Status in Handlern und Effekten, übergeben Sie Funktionsreferenzen, verwenden Sie Funktionsaktualisierungen und hängen Sie von Grundelementen oder gespeicherten Werten ab. Fügen Sie einconsole.log('render')hinzu Um die Schleife zu bestätigen, protokollieren Sie dann jede Abhängigkeit, um herauszufinden, welche sich ständig ändert – der Übeltäter ist normalerweise sofort erkennbar, sobald Sie ihn sehen.
🔗 Share this article
✍️ Leave a Comment