A component re-renders forever or an effect never stops firing
“The page freezes or the console says "Too many re-renders" or "Maximum update depth exceeded"; the network tab shows the same request firing over and over.”
ERROR CODES YOU MAY SEE
A code is a clue. Use its meaning and surrounding evidence to narrow the cause.
301React minified errors · libraryToo many re-renders. A component kept scheduling state updates during its own render, so React stopped to prevent an infinite loop.
Look for a setter called unconditionally in the component body or an event prop written as onClick={setX(v)} instead of onClick={() => setX(v)}.
Official reference for 301 (opens in new tab)Code definition reviewed185React minified errors · libraryMaximum update depth exceeded. Updates kept triggering nested updates (classically setState in componentDidUpdate; in hooks code, an effect or layout effect that sets state every commit).
Find the effect that sets state and log its dependencies across two renders; the one that fails Object.is is usually an object, array, or function recreated on every render.
Official reference for 185 (opens in new tab)Code definition reviewed
THE PRINCIPLE
Dependencies are compared with Object.is. Anything created during render is a new value every time, so an effect that depends on it and sets state will loop.
FIRST MOVES
- Read which error you have: "Too many re-renders" (301) means a setter ran during render; "Maximum update depth exceeded" (185) usually means an effect sets state on every commit.
- Check event props: onClick={setOpen(true)} calls the setter during render; it must be onClick={() => setOpen(true)}.
- Log the effect's dependency array across two renders and compare each entry with Object.is; the one that is false is the culprit.
- Move object and function construction inside the effect, or depend on primitives (ids, strings) instead of whole objects.
- Ask whether the effect is needed at all: derived values can be computed during render, and fetching usually belongs in a data library or framework loader.
TOOLS: THEN → NOW
PATTERN SNAPSHOT
// Loops: options is a new object every render, and the effect sets state.
const options = { roomId, filter };
useEffect(() => { load(options).then(setRows); }, [options]);
// Stable: depend on primitives and build the object inside the effect.
useEffect(() => {
let ignore = false;
load({ roomId, filter }).then((rows) => { if (!ignore) setRows(rows); });
return () => { ignore = true; };
}, [roomId, filter]);CLOSE THE AI. EXPLAIN THIS.
What two conditions must both hold for a useEffect to loop forever, and why does an inline object in the dependency array satisfy one of them?HOW IT WORKS UNDERNEATH
RELATED SYMPTOMS
SOURCES
- React: useEffect troubleshooting (infinite cycle, runs after every render) (opens in new tab)Checked
- React: You Might Not Need an Effect (opens in new tab)Checked
- React minified error #301 (Too many re-renders) (opens in new tab)Checked
- React minified error #185 (Maximum update depth exceeded) (opens in new tab)Checked
Guide reviewed