Loading lessons...
The Rules of Hooks
The Rules of Hooks
React Hooks (useState, useEffect, useContext, etc.) enable functional components to tap into React state and lifecycle features. However, React relies on strict internal execution call orders, leading to two fundamental Rules of Hooks.
Rule 1: Only Call Hooks at the Top Level
Do not call Hooks inside loops, conditions, nested functions, or try/catch blocks. Always use Hooks at the top level of your React function, before any early returns.
// ❌ WRONG: Calling Hook inside a condition
function Profile({ isLoaded }) {
if (isLoaded) {
// Error! Breaking top-level execution order!
useEffect(() => { fetchProfile(); }, []);
}
return <div>Profile</div>;
}
// ✅ CORRECT: Always call Hook at top level; place condition INSIDE the hook
function Profile({ isLoaded }) {
useEffect(() => {
if (isLoaded) {
fetchProfile();
}
}, [isLoaded]);
return <div>Profile</div>;
}
Why Top-Level Calling is Mandatory
React does not track state using variable names; it relies on the exact index order in which Hooks are called during component renders. If a condition skips a Hook call, all subsequent Hook call indices get misaligned, breaking component state memory!
Rule 2: Only Call Hooks from React Functions
Call Hooks exclusively from:
- React Functional Components.
- Custom Hooks (functions starting with
use...).
Do not call Hooks from regular JavaScript utility functions outside component lifecycles.
| Allowed Call Locations | Disallowed Call Locations |
|---|---|
| Top level of React Functional Component | Inside if / else conditional blocks |
Inside Custom Hook (useFetch, useAuth) | Inside for or while loops |
Top level before any early return statement | Inside standard non-React JS functions |
Summary & TL;DR
- Rule 1: Only call Hooks at the top level. Never inside conditions, loops, or nested functions.
- Rule 2: Only call Hooks from React functional components or custom Hooks.
- React relies on Hook call order consistency across renders.