How to fix React Hook "useState" is called conditionally in React
React Hook 'useState' is called conditionally, which violates the Rules of Hooks. Hooks must always be called at the top level of your component, before any early returns or conditional statements.
Quick fix
Fixes INVALID_HOOK_CALL
// ❌ WRONG - useState inside condition
function MyComponent({ isUser }) {
if (isUser) {
const [name, setName] = useState('');
}
return <div></div>;
}
// ✅ CORRECT - useState at top level
function MyComponent({ isUser }) {
const [name, setName] = useState('');
if (isUser) {
return <div>{name}</div>;
}
return <div>Not logged in</div>;
}- Move the state declaration to the top level
- Move conditions inside hooks instead
- Use separate components for different logic branches
- Verify with ESLint plugin
// ❌ WRONG - useState inside conditionfunction MyComponent({ isUser }) {if (isUser) {const [name, setName] = useState('');}return <div></div>;}// ✅ CORRECT - useState at top levelfunction MyComponent({ isUser }) {const [name, setName] = useState('');if (isUser) {return <div>{name}</div>;}return <div>Not logged in</div>;}React Hook "useState" is called conditionally
What this error means
In React, hooks like useState follow a specific rule: they must be called in the same order every time a component renders. React internally tracks hooks using an array, and when you call a hook conditionally (inside an if statement, loop, or after an early return), the order of hooks can change between renders. When the order changes, React cannot correctly match each hook call to its stored state, causing incorrect behavior or crashes. This is why React enforces the "Rules of Hooks" - to ensure hooks are always called in a consistent, predictable order.
Typical symptoms
- Error message: "React Hook \"useState\" is called conditionally"
- Components behave erratically after conditionally calling hooks
- State values become out of sync with their intended purpose
- Different number of hooks called on different renders
- ESLint warning from eslint-plugin-react-hooks plugin
Common causes
- Calling useState inside an if/else statement
- Calling useState inside a loop (for, while, etc.)
- Calling useState after an early return statement
- Calling useState inside nested functions or callbacks
- Toggling hook calls between renders based on conditions
How to fix "React Hook "useState" is called conditionally"
Call useState at the very top of your component function, before any conditional logic. This ensures the hook is always called in the same order.
// ❌ WRONG - useState inside condition
function MyComponent({ isUser }) {
if (isUser) {
const [name, setName] = useState('');
}
return <div></div>;
}
// ✅ CORRECT - useState at top level
function MyComponent({ isUser }) {
const [name, setName] = useState('');
if (isUser) {
return <div>{name}</div>;
}
return <div>Not logged in</div>;
}If you need conditional logic, move the condition inside the hook (useEffect, useMemo, etc.) rather than wrapping the hook itself.
// ❌ WRONG - conditional hook
function MyComponent({ shouldFetch }) {
if (shouldFetch) {
const [data, setData] = useState(null);
}
}
// ✅ CORRECT - condition inside hook
function MyComponent({ shouldFetch }) {
const [data, setData] = useState(null);
useEffect(() => {
if (shouldFetch) {
// Fetch logic here
}
}, [shouldFetch]);
}If you have completely different rendering logic, consider extracting each branch into its own component. Each component can have its own hooks.
// Component with hooks for authenticated users
function UserProfile() {
const [profile, setProfile] = useState(null);
// ... user-specific hooks
return <div>{profile.name}</div>;
}
// Component with hooks for guests
function GuestView() {
const [guestData, setGuestData] = useState(null);
// ... guest-specific hooks
return <div>Welcome, guest!</div>;
}
// Main component - conditional rendering of components, not hooks
function MyComponent({ isUser }) {
return isUser ? <UserProfile /> : <GuestView />;
}Make sure you have eslint-plugin-react-hooks installed and configured. This will catch violations automatically.
npm install --save-dev eslint-plugin-react-hooksAdd to your .eslintrc.json:
{
"plugins": ["react-hooks"],
"rules": {
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn"
}
}Advanced notes
The Rules of Hooks exist because of how React implements hooks internally. React maintains a "fiber" (component instance) with a linked list of hooks. Each hook occupies a fixed position in this list. When you call hooks conditionally, React cannot guarantee that the same hook will be at the same position on every render, causing state and effects to be associated with the wrong hooks.
This is why the order of hooks must be deterministic and unconditional. The only way to conditionally run a hook's effect is to move the condition inside the hook itself, typically using useEffect with a dependency array.
Remember: Hooks can only be called at the top level or inside custom hooks (which themselves must follow the same rules). They cannot be called in classes, regular functions, or nested functions outside of hooks.
Frequently asked questions
- What does "INVALID_HOOK_CALL" mean?
- In React, hooks like useState follow a specific rule: they must be called in the same order every time a component renders. React internally tracks hooks using an array, and when you call a hook conditionally (inside an if statement, loop, or after an early return), the order of hooks can change between renders. When the order changes, React cannot correctly match each hook call to its stored state, causing incorrect behavior or crashes.
- How do I fix "INVALID_HOOK_CALL"?
- React Hook 'useState' is called conditionally, which violates the Rules of Hooks. Hooks must always be called at the top level of your component, before any early returns or conditional statements.
- What causes "INVALID_HOOK_CALL"?
- Calling useState inside an if/else statement Calling useState inside a loop (for, while, etc.) Calling useState after an early return statement
- Is the "INVALID_HOOK_CALL" error serious?
- Yes. This is a high-severity error that usually blocks work until it is fixed, but the steps above resolve it.
Official resources & further reading
- 📚React Official Documentation
- 📖Rules of Hooks - React official documentation(Official Docs)
- 📖Invalid Hook Call Warning - React(Official Docs)