React's Rules of Hooks are two constraints that every Hook call must follow. React tracks each Hook's state by call order, so a Hook that runs conditionally can quietly attach state to the wrong component.
The two rules
First, call Hooks only at the top level of your component or custom Hook. Second, call Hooks only from React function components or custom Hooks. Both rules protect the call order that React depends on.
- No Hooks inside conditions, loops, or nested functions.
- No Hooks after an early return.
- No Hooks in event handlers or class components.
- No Hooks in regular JavaScript functions.
- No Hooks inside functions passed to useMemo, useReducer, or useEffect.
These rules exist because React relies on call order.
Why call order matters
When a component renders, React records each Hook call in the order it runs. It stores state for the first useState call, then the second, and returns them in that same order on the next render.
function Profile() {
const [name, setName] = useState("Ada");
const [age, setAge] = useState(30);
return (
<p>
{name} is {age}
</p>
);
}On every render, React expects call one to hold the name state and call two to hold the age state. If a condition skips one call on a later render, the order shifts and React hands the age value to the variable that expected name. A single skipped call desynchronizes every Hook that follows it.
Keep conditions inside the Hook
You cannot wrap a Hook call in an if statement, but the rendering logic can still be conditional. Put the Hook calls before the return, then branch afterward.
function Profile({ showAge }) {
const [name, setName] = useState("Ada");
const [age, setAge] = useState(30);
if (!showAge) {
return <p>{name}</p>;
}
return <p>{name} is {age}</p>;
}Both useState calls run before the conditional return, so their order never changes. The early return only controls what renders, not which Hooks run. When a condition must decide between Hooks, move the condition inside the Hook instead.
Only call Hooks from React functions
Custom Hooks count as React functions, so a Hook may call other Hooks. Regular JavaScript functions cannot call Hooks, which keeps stateful logic visible inside components and custom Hooks.
Moving a useState call into a plain helper function triggers a lint error, because the plugin cannot guarantee call order there. If a helper does call a Hook, rename it with the use prefix so the plugin treats it as a Hook.
The eslint-plugin-react-hooks plugin catches both rules automatically. Configure it in your lint setup, and a violation shows up as a lint error instead of a runtime bug.
Learn how to create a custom Hook and what it means to reuse stateful logic without sharing state.
Rune AI
Key Insights
- Call Hooks only at the top level, before any early return.
- Never call Hooks inside conditions, loops, or nested functions.
- Call Hooks only from function components or custom Hooks.
- React matches Hooks to state by call order.
- Configure eslint-plugin-react-hooks to catch violations automatically.
Frequently Asked Questions
What are the two Rules of Hooks?
Why do Hooks have to be called in the same order?
Can I call a Hook inside an if statement?
Conclusion
The Rules of Hooks exist because React matches each Hook to its state by call order. Keep Hooks at the top level of components and custom Hooks, and let the eslint plugin catch violations before they reach runtime.
More in this topic
How to Build a Dropdown Menu in React
Build a React dropdown menu with the ARIA menu button pattern. Handle open and close, keyboard arrows, and clicks outside the menu.
How to Animate React Components with Motion
Animate React components with the Motion library. Set up motion, add enter, hover, and exit animations, and respect reduced motion.
Headless UI Components Explained: Logic Without Locked Styling
Understand headless UI components and how libraries like Radix give you unstyled, accessible behavior that you style yourself.