QuestionsReact

Rules of Hooks — and why

Hooks RulesEasyReact

What are the rules of hooks? Why can't you call a hook inside a condition?

What it tests

Whether you understand hooks are matched by call ORDER, not by name.

Approach & answer

Two rules: call hooks only at the top level (never in conditions, loops, or nested functions), and only from React functions. React tracks hook state by the ORDER of calls on each render — it has no names to go by. If a condition skips a useState on some renders, every subsequent hook shifts by one slot and reads the wrong state. Keeping calls unconditional keeps the order stable. Mechanically, React keeps a linked list (or array) of hook 'cells' per component instance and walks it in the same sequence every render; the Nth useState call always maps to the Nth cell. That's why the fix is always to branch INSIDE the hook, not around it — put the condition in the effect body, or pass a conditional dependency, or early-return AFTER all hooks. The eslint-plugin-react-hooks rules (rules-of-hooks + exhaustive-deps) catch the vast majority of violations at lint time; treat exhaustive-deps warnings as correctness bugs, not style nits. Custom hooks inherit the same rules because they're just functions that call hooks, which is also why they must be named useSomething so the linter can recognize them.

Use this technique when

Explaining a 'rendered fewer hooks than expected' error, and why you branch INSIDE a hook, not around it.

Code

// WRONG: conditional hook shifts the order
if (loggedIn) { const [x] = useState(0); }

// RIGHT: hook is unconditional; branch inside
const [x, setX] = useState(0);
if (loggedIn) { /* use x */ }

References