100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
React

Rules of Hooks

Learn the two Rules of Hooks — only call at the top level, only call from React functions — and why they exist.

Hooks FundamentalsIntermediate8 min readJul 8, 2026
Analogies

Introduction

React Hooks work correctly only if they are called in a predictable, consistent way on every render. To guarantee this, React defines two strict Rules of Hooks. Breaking either rule leads to subtle bugs, such as state being assigned to the wrong variable or effects firing at the wrong time, so the eslint-plugin-react-hooks package enforces these rules automatically during development.

🏏

Cricket analogy: A bowler must deliver the same run-up and action every ball for the umpire to judge fairly; if Bumrah suddenly changed his approach mid-delivery, the whole rhythm breaks, which is why Hooks need a fixed, predictable calling pattern every render.

Syntax

jsx
// Rule 1: Only call Hooks at the top level
function Component() {
  const [a, setA] = useState(0); // top level - OK
  useEffect(() => { /* ... */ }); // top level - OK
  return <div>{a}</div>;
}

// Rule 2: Only call Hooks from React functions
function useCustomHook() {
  const [value, setValue] = useState(null); // custom Hook - OK
  return value;
}

Explanation

Rule 1 — Only call Hooks at the top level: never call Hooks inside loops, conditions, nested functions, or after an early return. Rule 2 — Only call Hooks from React function components or from custom Hooks (functions whose name starts with 'use'); never call them from regular JavaScript functions, class components, or event handler callbacks directly. Both rules exist because React does not track Hooks by name — it tracks them by call order. Internally, each component instance keeps a linked list (or array) of Hook 'slots' populated in the exact sequence the Hooks were called during the first render. On every subsequent render, React walks that same list in order, matching the Nth useState call to the Nth slot, the Nth useEffect call to the Nth slot, and so on. If a Hook call is conditionally skipped on some renders (e.g., inside an if block or after an early return), the call order shifts, and React ends up associating the wrong state or effect with the wrong slot — corrupting component state in ways that are very hard to debug. Keeping Hooks unconditional at the top level guarantees the same number and order of calls on every render, keeping the slot-to-Hook mapping stable.

🏏

Cricket analogy: A scorer tracks each over by ball number in a fixed sequence in the scorebook; if a no-ball is skipped without recording it, every subsequent ball's slot shifts and the whole scorecard misaligns, just like a skipped Hook shifts React's slot list.

Example

jsx
// WRONG: Hook called conditionally
function Bad({ isLoggedIn }) {
  if (isLoggedIn) {
    const [user, setUser] = useState(null); // breaks call order between renders
  }
  useEffect(() => { /* ... */ });
  return <div />;
}

// CORRECT: Hook always called, condition moved inside
function Good({ isLoggedIn }) {
  const [user, setUser] = useState(null); // always called
  useEffect(() => {
    if (isLoggedIn) {
      // conditional logic goes inside the Hook, not around it
      fetchUser().then(setUser);
    }
  }, [isLoggedIn]);
  return <div />;
}

Output

In the 'Bad' component, if isLoggedIn is true on one render and false on the next, the number of Hook calls changes between renders. React will throw a runtime error ('Rendered fewer hooks than expected') or silently misalign state, since the useEffect call now occupies a different slot index than before. The 'Good' component calls useState unconditionally every render and instead puts the conditional logic inside the effect body, keeping the Hook call order identical across all renders and avoiding the bug entirely.

🏏

Cricket analogy: If a captain fields only ten players when the opposition's star batter is on strike and eleven otherwise, the umpire will flag the mismatch immediately, just as React throws 'Rendered fewer hooks than expected' when isLoggedIn changes the Hook count.

Key Takeaways

  • Rule 1: only call Hooks at the top level — never inside loops, conditions, nested functions, or after an early return.
  • Rule 2: only call Hooks from React function components or from custom Hooks, never from plain functions or classes.
  • Both rules exist because React matches Hooks to state using call order, not by name.
  • Conditionally skipping a Hook call shifts every subsequent Hook's slot index, corrupting component state.
  • Move conditional logic inside the Hook body (e.g., inside useEffect) rather than wrapping the Hook call itself in a condition.
  • The eslint-plugin-react-hooks 'rules-of-hooks' rule catches most violations automatically during development.

Practice what you learned

Was this page helpful?

Topics covered

#React#ReactJsStudyNotes#WebDevelopment#RulesOfHooks#Rules#Hooks#Syntax#Explanation#StudyNotes#SkillVeris