Error: Maximum update depth exceeded. This can happen when a component
repeatedly calls setState inside componentDidUpdate or useEffect.
A component is updating state in a way that triggers another update, creating an infinite loop.
Fix 1: Calling Function Instead of Passing Reference
// ❌ Calls handleClick immediately on every render
<button onClick={handleClick()}>Click</button>
// ✅ Pass the function reference
<button onClick={handleClick}>Click</button>
// ✅ If you need to pass arguments
<button onClick={() => handleClick(id)}>Click</button>
Fix 2: setState in useEffect Without Dependencies
// ❌ Runs on every render, sets state, triggers re-render...
useEffect(() => {
setCount(count + 1);
});
// ✅ Add a dependency array
useEffect(() => {
setCount(count + 1);
}, []); // Run once
Fix 3: Object/Array in Dependency Array
// ❌ New object every render → useEffect runs every time
useEffect(() => {
fetchData(filters);
}, [{ status: 'active' }]); // 💥 New object reference each render
// ✅ Use primitive values or useMemo
const filters = useMemo(() => ({ status: 'active' }), []);
useEffect(() => {
fetchData(filters);
}, [filters]);
Fix 4: setState During Render
// ❌ Setting state directly in the component body
function Counter() {
const [count, setCount] = useState(0);
setCount(count + 1); // 💥 Infinite loop
// ✅ Use useEffect or event handlers
}
Fix 5: Parent Re-Renders Child Infinitely
// ❌ Parent passes new callback every render
function Parent() {
return <Child onChange={(val) => console.log(val)} />;
}
// ✅ Memoize the callback
function Parent() {
const handleChange = useCallback((val) => console.log(val), []);
return <Child onChange={handleChange} />;
}
Debugging
// Add a render counter to find the looping component
function MyComponent() {
const renderCount = useRef(0);
renderCount.current++;
console.log(`Rendered ${renderCount.current} times`);
}