How to fix Warning: React Hook was called conditionally. React Hooks must be called in the exact same order in every component render. in React
This React warning occurs when you call hooks inside conditions, loops, or after early returns, violating the Rules of Hooks. React requires hooks to be called in the same order on every render to maintain state consistency.
Quick fix
Fixes Warning: React Hook was called conditionally. React Hooks must be called in the exact same order in every component render.
function MyComponent({ isLoggedIn }) {
if (!isLoggedIn) {
return <Login />;
}
// ❌ Hook called after conditional return
const [data, setData] = useState(null);
return <Dashboard data={data} />;
}- Move all hook calls to the top of your component
- Move conditional logic inside hooks, not around them
- Use null or undefined for conditional state initialization
- Split components if you have genuinely different render paths
function MyComponent({ isLoggedIn }) {if (!isLoggedIn) {return <Login />;}// ❌ Hook called after conditional returnconst [data, setData] = useState(null);return <Dashboard data={data} />;}Warning: React Hook was called conditionally. React Hooks must be called in the exact same order in every component render.
What this error means
This warning occurs when you violate one of React's fundamental Rules of Hooks by calling a hook conditionally. React Hooks must always be called at the top level of your component function, before any early returns, and in the same order on every render. React uses the order of hook calls to track state and effects between renders. When you call hooks conditionally or after early returns, React can't guarantee the same call order on every render, breaking its internal state management system. React stores hooks in a linked list, with each hook call adding a new object in a strict sequence. If this sequence changes between renders, React loses track of which state belongs to which hook. This rule applies to all hooks including useState, useEffect, useContext, useCallback, useMemo, useRef, and custom hooks. Breaking this rule can lead to state corruption, incorrect behavior, and hard-to-debug issues in your application.
Typical symptoms
- Warning message in browser console: "React Hook was called conditionally"
- Component state behaving incorrectly or unpredictably
- React DevTools showing warning about invalid hook call
- ESLint error if using eslint-plugin-react-hooks
- Component re-rendering with corrupted or swapped state values
- Effects running at unexpected times or not at all
Common causes
- Calling a hook inside an if statement or conditional block
- Using hooks after an early return statement in a component
- Placing hook calls inside loops (for, while, map)
- Calling hooks inside nested functions that may not execute every render
- Using hooks inside try-catch blocks where execution path varies
- Conditionally calling custom hooks that contain other hooks
How to fix "Warning: React Hook was called conditionally. React Hooks must be called in the exact same order in every component render."
Ensure all hooks are called before any conditional logic or early returns. This is the most common fix.
Before (incorrect):
function MyComponent({ isLoggedIn }) {
if (!isLoggedIn) {
return <Login />;
}
// ❌ Hook called after conditional return
const [data, setData] = useState(null);
return <Dashboard data={data} />;
}After (correct):
function MyComponent({ isLoggedIn }) {
// ✅ Hook called at the top level
const [data, setData] = useState(null);
if (!isLoggedIn) {
return <Login />;
}
return <Dashboard data={data} />;
}If you need conditional behavior, put the condition inside the hook rather than conditionally calling the hook.
For useEffect:
// ❌ Wrong - conditionally calling the hook
if (shouldFetch) {
useEffect(() => {
fetchData();
}, []);
}
// ✅ Correct - condition inside the hook
useEffect(() => {
if (shouldFetch) {
fetchData();
}
}, [shouldFetch]);
// ✅ Also correct - early return inside the hook
useEffect(() => {
if (!shouldFetch) return;
fetchData();
}, [shouldFetch]);When you need conditional initialization, use a default value that works for all cases.
// ❌ Wrong - conditionally calling useState
function UserProfile({ userId }) {
if (userId) {
const [user, setUser] = useState(null);
}
// ...
}
// ✅ Correct - always call useState
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
useEffect(() => {
if (userId) {
fetchUser(userId).then(setUser);
}
}, [userId]);
if (!user) return <Loading />;
return <div>{user.name}</div>;
}If your component has fundamentally different logic based on conditions, consider splitting it into separate components.
// ❌ Wrong - trying to use hooks conditionally
function DashboardOrLogin({ isLoggedIn }) {
if (isLoggedIn) {
const [data, setData] = useState(null);
return <Dashboard data={data} />;
} else {
const [email, setEmail] = useState('');
return <Login email={email} onChange={setEmail} />;
}
}
// ✅ Correct - split into separate components
function Dashboard() {
const [data, setData] = useState(null);
return <div>{/* dashboard UI */}</div>;
}
function Login() {
const [email, setEmail] = useState('');
return <form>{/* login form */}</form>;
}
function App({ isLoggedIn }) {
return isLoggedIn ? <Dashboard /> : <Login />;
}Use the official ESLint plugin to catch these errors during development.
Install the plugin:
npm install eslint-plugin-react-hooks --save-devConfigure in .eslintrc.json:
{
"plugins": ["react-hooks"],
"rules": {
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn"
}
}This will show errors in your IDE before you even run the code, catching violations of the Rules of Hooks immediately.
Advanced notes
Why React uses call order instead of IDs:
React deliberately chose to track hooks by their call order rather than by unique IDs because it keeps the hooks API simple and prevents naming conflicts. Using call order means you don't need to name each hook call, and React can automatically manage the state array efficiently.
Custom hooks must follow the same rules:
When you create custom hooks, they must also follow the Rules of Hooks. Any hook that calls other hooks internally must be called unconditionally. The hook name must start with "use" so ESLint can enforce these rules.
Loops and hooks:
Never call hooks inside loops because the number of iterations might change between renders:
// ❌ Wrong
items.map(item => {
const [state, setState] = useState(item.value);
// ...
});
// ✅ Correct - one component per item
items.map(item => <ItemComponent key={item.id} item={item} />);Try-catch and hooks:
Avoid wrapping hook calls in try-catch blocks where the execution path might vary. Instead, handle errors inside the hook:
// ✅ Handle errors inside useEffect
useEffect(() => {
try {
fetchData();
} catch (error) {
console.error(error);
}
}, []);React Compiler (future):
The upcoming React Compiler may help catch some of these issues at build time, but the Rules of Hooks will still apply as they're fundamental to how React works.
Frequently asked questions
- What does "Warning: React Hook was called conditionally. React Hooks must be call" mean?
- This warning occurs when you violate one of React's fundamental Rules of Hooks by calling a hook conditionally. React Hooks must always be called at the top level of your component function, before any early returns, and in the same order on every render. React uses the order of hook calls to track state and effects between renders.
- How do I fix "Warning: React Hook was called conditionally. React Hooks must be call"?
- This React warning occurs when you call hooks inside conditions, loops, or after early returns, violating the Rules of Hooks. React requires hooks to be called in the same order on every render to maintain state consistency.
- What causes "Warning: React Hook was called conditionally. React Hooks must be call"?
- Calling a hook inside an if statement or conditional block Using hooks after an early return statement in a component Placing hook calls inside loops (for, while, map)
- Is the "Warning: React Hook was called conditionally. React Hooks must be call" error serious?
- It is a medium-severity error — more of a blocker than a risk. The steps above resolve it.
Official resources & further reading
- 📚React Official Documentation
- 📖React Official Docs: Rules of Hooks(Official Docs)
- 📖React Legacy Docs: Rules of Hooks(Official Docs)