Minified React error #321
React JavaScript Framework
Severity: CriticalWhat Does This Error Mean?
Minified React error #321 is the production version of: 'Rendered more hooks than during the previous render.' It means the number of hooks (useState, useEffect, etc.) called during one render was different from a previous render. React requires hooks to always be called in the same order, every single render — no exceptions. Calling a different number of hooks breaks React's internal tracking.
Affected Models
- React 16.8 and later
- All React function components using hooks
Common Causes
- A hook is placed inside an if statement — it runs on some renders but not others, changing the hook count
- A hook is placed inside a for loop or while loop — the number of iterations (and therefore hook calls) changes between renders
- A hook is placed after an early return statement — if the early return fires, the hooks below it are skipped
- A hook is conditionally called based on props or state that can change — for example, if (props.enabled) useState(...)
- A component was converted from a class component to a function component but the hooks were not reorganised to be unconditional
How to Fix It
-
Find the hook that is being called conditionally. Look for any useState, useEffect, useRef, useMemo, useCallback, or useContext inside an if block, a loop, or after a return statement.
The error message in development mode (non-minified) names the specific hook that changed position — read it carefully.
-
Move all hooks to the top of your component function, before any if statements or early returns. Hooks must be the first things called, unconditionally, every time.
Wrong: if (isLoaded) { const [x, setX] = useState(0); }. Right: const [x, setX] = useState(0); then later: if (isLoaded) { ... use x ... }
-
If you only want to use a hook's result sometimes, call the hook unconditionally but use its value conditionally. The hook itself must always run — what you do with the result can be conditional.
Example: const [count, setCount] = useState(0); — always called. Then: if (showCount) return <div>{count}</div>; — the conditional is on the output, not the hook.
-
If you need hooks inside a condition, extract the conditional section into its own component. That child component can then use hooks freely — each component has its own hook call order.
Example: Create a <LoggedInUser /> component that internally uses useState and useEffect. The parent only renders <LoggedInUser /> when the condition is true.
-
Install the eslint-plugin-react-hooks plugin. It catches Rules of Hooks violations at code-writing time with a lint error, before you even run the app.
Most React project templates include this already. Run: npm install eslint-plugin-react-hooks --save-dev. It will highlight the problem line immediately in your editor.
When to Call a Professional
This error is always a code structure problem you can fix yourself. The Rules of Hooks are strict but simple: always call hooks at the top level of your component, never inside conditions or loops.
Frequently Asked Questions
Why does React require hooks to always be called in the same order?
React does not store hook state by name — it stores it by call position. The first useState call always corresponds to the first slot of state, the second useState to the second slot, and so on. If you skip a hook call, every subsequent hook gets the wrong state — like pulling the wrong drawer because someone removed a drawer from the middle of a cabinet. Keeping hooks unconditional is what makes this reliable.
Can I use hooks inside a custom hook?
Yes — custom hooks are just regular JavaScript functions whose name starts with 'use'. Inside a custom hook, you can call any other hooks, including useState, useEffect, and other custom hooks. The same rules apply inside custom hooks: hooks must be called unconditionally, at the top level, in the same order every time the custom hook is called.
What is the difference between error #321 and the 'fewer hooks than previous render' error?
They are mirror images of the same problem. Error #321 means MORE hooks were called this render than last time — a hook was added that was not there before. The 'fewer hooks' error means FEWER hooks were called — a hook was skipped that ran before. Both are violations of the Rules of Hooks. The fix is the same: move all hooks to the unconditional top level of your component.