The "Maximum update depth exceeded" error occurs when React detects a component is stuck in an infinite update loop. This typically happens when useEffect or componentDidUpdate triggers a state update that causes a re-render, which triggers the effect again "” endlessly.
// ❌ Problem "” no dependency array, infinite loop
useEffect(() => {
setCount(count + 1); // Sets state → re-render → effect runs again
});
// ✅ Solution 1 "” empty array, runs once
useEffect(() => {
setCount(1);
}, []);
// ✅ Solution 2 "” functional update, no dependency needed
useEffect(() => {
setCount(prev => prev + 1);
}, []); // Only runs on mount
function Timer() {
const [time, setTime] = useState(0);
// ❌ No dependency array "” runs after every render
useEffect(() => {
setTime(time + 1); // Sets state → re-render → effect runs → infinite!
});
return <div>{time}</div>;
}
function Timer() {
const [time, setTime] = useState(0);
// ✅ Use setInterval with cleanup
useEffect(() => {
const interval = setInterval(() => {
setTime(prev => prev + 1); // Functional update "” no dependency needed
}, 1000);
return () => clearInterval(interval); // Cleanup
}, []); // Empty array "” runs once on mount
return <div>{time}</div>;
}
function Search({ query }) {
const [results, setResults] = useState([]);
const filters = { query, page: 1 }; // ❌ New object every render!
useEffect(() => {
fetchResults(filters).then(setResults);
}, [filters]); // filters changes every render → infinite loop!
}
function Search({ query }) {
const [results, setResults] = useState([]);
// ✅ Use primitive values as dependencies
useEffect(() => {
fetchResults({ query, page: 1 }).then(setResults);
}, [query]); // Only re-run when query string changes
}
// ✅ Or memoize the object
const filters = useMemo(() => ({ query, page: 1 }), [query]);
function Parent() {
const [data, setData] = useState(null);
// ❌ New function reference every render
const onLoad = (result) => setData(result);
return <Child onLoad={onLoad} />;
}
function Child({ onLoad }) {
useEffect(() => {
fetchData().then(onLoad);
}, [onLoad]); // onLoad changes every render → infinite loop!
}
function Parent() {
const [data, setData] = useState(null);
// ✅ Stable reference with useCallback
const onLoad = useCallback((result) => setData(result), []);
return <Child onLoad={onLoad} />;
}
const [items, setItems] = useState([]);
// ❌ items in deps + setItems → infinite loop
useEffect(() => {
setItems([...items, newItem]);
}, [items]);
// ✅ Use functional update "” no need to list items as dependency
useEffect(() => {
setItems(prev => [...prev, newItem]);
}, [newItem]); // Only depends on newItem
This error occurs when useEffect triggers a state update that causes a re-render, which triggers the effect again, creating an infinite loop. Common causes: no dependency array, objects in deps, or state that depends on itself.
"Too many re-renders" usually means setState is called during the render phase. "Maximum update depth exceeded" means useEffect is causing an infinite update cycle after rendering.
Objects are compared by reference in JavaScript. A new object {} !== {} even with identical content. So React sees the dependency as changed on every render, re-running the effect endlessly.
Instead of setCount(count + 1), use setCount(prev => prev + 1). This reads the latest state without needing count in the dependency array, breaking the loop.
Add console.log inside the effect to count how many times it runs. Check the dependency array for objects/arrays. Use React DevTools Profiler to see which component is re-rendering excessively.
Explore 500+ free tutorials across 20+ languages and frameworks.