Rendered more hooks than during the previous render
Filed under Next.js & React errors
A hook is called conditionally — inside an if, a loop, or below an early return — so different renders call different numbers of hooks.
Fastest route
Give your AI this prompt
Copy it, replace the bracketed part with your error, and send it.
Preview the prompt
I am getting a React error: "Rendered more hooks than during the previous render" (in production it may appear as Minified React error #310). Here is the full component: [paste the component code]. Please: 1) find every hook (useState, useEffect, useMemo, useRef, and custom hooks) that is called conditionally — inside an if, a ternary, a loop, a map callback, a plain helper function, or below an early return, 2) rewrite the component so all hooks run unconditionally at the top, in the same order every render, moving any conditions inside the hooks, 3) if a hook sits in a list loop, extract a child component for the item instead. Constraints: change nothing about what the component does or shows, do not rename state or alter the logic, and show me which hook was conditional before you rewrite it.
Fix it yourself
Follow the repair
- Understand the one rule behind the error. React matches hooks between renders by order, like numbered seats in a row. Render one: three hooks take seats 1, 2, 3. Render two must seat the same three hooks in the same order. Any change in count means someone is sitting in the wrong seat, and React stops the show rather than hand the wrong state to the wrong hook.
- Hunt for early returns sitting above a hook. Scan the component top to bottom and note every
returnthat can happen before the end. This shape is the number-one cause:
Whilefunction Profile({ userId }) { const { data, loading } = useUser(userId); if (loading) return <p>Loading…</p>; // returns early const [tab, setTab] = useState("posts"); // hook BELOW the return — bug ... }loadingis true,useStatenever runs. The moment loading finishes, it does — one more hook than the previous render. - Move every hook above any conditional return. Gather all the hooks — every
useState,useEffect,useMemo, and custom hook — into a flat block at the top of the component, before the firstifthat can return. The guards and early returns move down below them:function Profile({ userId }) { const [tab, setTab] = useState("posts"); // hooks first, always const { data, loading } = useUser(userId); if (loading) return <p>Loading…</p>; // returns after the hooks ... } - Move conditions inside the hooks instead. When the work should only happen sometimes, keep the hook unconditional and gate the work:
The hook runs on every render; the activity load runs only when it should. The same trick works for computed values: calculate with a fallback instead of conditionally callinguseEffect(() => { if (!userId) return; // condition inside the hook loadActivity(userId); }, [userId]);useMemo. - Check loops, map callbacks, and helper functions. A hook inside a
.map()runs once per item, so adding an item changes the count. If each row needs its own state or effect, extract the row into its own component —<Row key={item.id} item={item} />— and call the hook at the top ofRow, where it runs unconditionally once per component. Likewise, a hook buried in a plain helper function should move into the component, or the helper should be renamed and treated as a custom hook (starting withuse) that the component calls every render. - If it appeared after an AI edit, compare what moved. Builders "cleaning up" a component often nest a hook inside a condition or slide it below a guard clause, and the error shows up immediately after. Review the last change, restore the hooks to a flat, top-level row in their original order, and confirm the page renders through the state change that used to crash it — toggle the loading state, sign in, empty the list — before asking for anything new.
Why this happensOptional explanation
Hooks — useState, useEffect, and their relatives — have no names React can look them up by. Instead, React identifies each one purely by position: the first hook called during a render gets the first slot of state, the second gets the second slot, and so on. That system only works if every render calls exactly the same hooks in exactly the same order. The moment one render calls an extra hook — or skips one — every slot after it lines up with the wrong state, so React refuses to continue and throws this error instead.
The trigger is almost always a hook whose execution depends on something that changes. An early return for a loading spinner placed above a useEffect. A useState inside an if that checks whether a user is signed in. A hook inside a list loop that runs once per item — and the item count changed. The code can sit there looking innocent for days, because the error only fires on the render where the condition flips for the first time: loading finishes, the user logs in, the list grows. That is why it so often seems to appear "out of nowhere" during testing rather than on the first page load.
- Early return above a hook: the loading or error guard returns before the hooks below it run.
- Hook inside a condition: an if, a ternary, or a && expression decides whether the hook runs at all.
- Hook inside a loop or map: the hook count grows and shrinks with the list.
- Hook inside a plain helper: a function that is not a component or a custom hook only runs when called.
Quick answers
I didn't touch any hooks. Why did this appear out of nowhere?
Because the bug only fires when the code path changes. The conditional hook sat harmlessly in the branch nobody took — until a state change (loading finished, a user signed in, a list emptied) sent a render down the other path and the hook count shifted. The mistake was there all along; the state change exposed it.
What about "Rendered fewer hooks than expected"?
It is the same rule broken in the opposite direction: one render called fewer hooks than the render before it, usually an early return or a condition that started skipping a hook. Find the hook whose execution depends on anything that can change, and make it unconditional.
Can I call a hook inside useEffect or an onClick handler?
Never. Hooks can only run at the top level of a component or a custom hook — not inside effects, click handlers, conditions, or loops. If a piece of logic needs to run on an event, put plain code in the handler; if it needs a hook's power, restructure so the hook runs every render and the condition lives inside it.