Skip to content

React Tutorial React Hooks

The Rules of Hooks in React

Lesson 58 of 156 2 min read By Deepak Paswan Updated Oct 10, 2026

Runnable lesson · press Try it on the examples to edit and run them here.

Hooks are ordinary functions with two special rules. Break them and React cannot match each hook call to its stored value, so you get errors or strange bugs. The rules are short, and they make sense once you see how React keeps track of hooks.

What is a hook?

A hook is a function whose name starts with use: useState, useEffect, useRef, useContext and more, plus your own custom hooks. Hooks let function components use React features such as state and lifecycle.

Rule 1: only call hooks at the top level

Do not call hooks inside loops, conditions, nested functions, try/catch/finally blocks or after an early return. Always call them at the top level of your component, in the same order on every render.

App.jsx
JSX
function Profile({ userId }) {
  if (!userId) {
    return <p>No user</p>;     // early return...
  }
  const [name, setName] = useState("");  // ...before a hook: broken!
  // ...
}

The fix is to call all hooks first, then return:

App.jsx
JSX
function Profile({ userId }) {
  const [name, setName] = React.useState(""); // hooks first

  if (!userId) {
    return <p>No user</p>;
  }
  return <p>User {userId}: {name}</p>;
}

function App() {
  return <Profile userId={null} />;
}

Why the rule exists

React does not know your variable names. It remembers state by the order of the hook calls: “first useState in this component, second useState…” Each render, it hands out values in that same order. If a condition skips a hook on one render, every hook after it receives the wrong value. That is why the order must never change.

Rule 2: only call hooks from React functions

Call hooks from:

  • function components (names starting with a capital letter), or
  • custom hooks (functions whose names start with use).

Not from ordinary JavaScript helper functions, event handlers or class components.

App.jsx
JSX
function handleClick() {
  const [x, setX] = useState(0);  // wrong: inside an event handler
}

What to do when you need a condition

  • To use state only in some cases, always call the hook and decide when to use the value.
  • To run an effect only sometimes, put the if inside the effect function.
  • To render a different component for different cases, put the hook in the child component that needs it.
App.jsx
JSX
function App() {
  const [enabled, setEnabled] = React.useState(false);

  React.useEffect(() => {
    if (!enabled) return;          // condition INSIDE the effect, not around the hook
    console.log("enabled!");
  }, [enabled]);

  return (
    <div>
      <p>Hello, Ada</p>
      <button onClick={() => setEnabled(!enabled)}>Toggle effect</button>
    </div>
  );
}

Let the linter help

You do not have to remember all of this. The Vite React template includes an Oxlint rule, react/rules-of-hooks, that reports a hook called conditionally. Keep it on. ESLint’s eslint-plugin-react-hooks does the same job in other setups.

The error message

If you break the rule, React may show: “Rendered more hooks than during the previous render” or “React has detected a change in the order of Hooks”. When you see either, look for a hook after a condition or an early return.

Key points

  • Call hooks only at the top level of components and custom hooks, never conditionally.
  • React finds each hook’s value by call order, so the order must be the same every render.
  • Put conditions inside hooks (such as inside an effect), not around them.