The "Too many re-renders" error occurs when React detects an infinite rendering loop. This happens when a component keeps triggering state updates during rendering, causing React to re-render endlessly until it hits its limit and throws this error.
// ❌ Problem "” calling setState during render
function App() {
const [count, setCount] = useState(0);
setCount(count + 1); // Infinite loop!
return <div>{count}</div>;
}
// ✅ Solution "” only call setState in event handlers or useEffect
function App() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(c => c + 1)}>
{count}
</button>
);
}
The most common mistake "” calling the function immediately instead of passing a reference.
// ❌ setCount(0) is called immediately during render!
<button onClick={setCount(0)}>Reset</button>
// ❌ handleClick() is called immediately during render!
<button onClick={handleClick()}>Click</button>
// ✅ Pass a function reference, not a call
<button onClick={() => setCount(0)}>Reset</button>
// ✅ Pass the function reference directly
<button onClick={handleClick}>Click</button>
// ❌ Runs after every render → sets state → triggers render → infinite loop
useEffect(() => {
setData(fetchData()); // No dependency array!
});
// ✅ Empty array = run only once on mount
useEffect(() => {
setData(fetchData());
}, []); // Add dependency array
// ✅ Run only when specific value changes
useEffect(() => {
setData(fetchData(userId));
}, [userId]); // Only re-run when userId changes
// ❌ options is a new object on every render → infinite loop
const options = { page: 1, limit: 10 };
useEffect(() => {
fetchData(options);
setResults(data);
}, [options]); // options changes every render!
// ✅ Use primitive values as dependencies
const [page, setPage] = useState(1);
const limit = 10;
useEffect(() => {
fetchData({ page, limit });
setResults(data);
}, [page]); // Primitive value "” stable reference
// ✅ Or memoize the object
const options = useMemo(() => ({ page: 1, limit: 10 }), []);
function Counter() {
const [count, setCount] = useState(0);
setCount(count + 1); // ❌ Called during render!
return <div>{count}</div>;
}
function Counter() {
const [count, setCount] = useState(0);
// ✅ Only update state in response to events
return (
<button onClick={() => setCount(c => c + 1)}>
Count: {count}
</button>
);
}
This error occurs when React detects an infinite rendering loop, usually caused by calling setState during the render phase, incorrect event handler syntax, or useEffect without a proper dependency array.
Wrap it in an arrow function: onClick={() => setState(value)}. Without the arrow function, setState is called immediately during render instead of when the button is clicked.
If useEffect has no dependency array, it runs after every render. If it sets state, that triggers another render, creating an infinite loop. Add [] for mount-only or list specific dependencies.
Use React DevTools Profiler to see which component re-renders. Add console.log in the render body to count renders. Check for setState calls outside event handlers and useEffect dependency arrays.
Yes! Objects and arrays are compared by reference in JavaScript. A new object {} !== {} even with the same content, so React sees it as changed every render. Use primitive values or useMemo to stabilize references.
Explore 500+ free tutorials across 20+ languages and frameworks.