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.
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.
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"
}
}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.
Prop spreading could cause security issues
Prop spreading could cause security issues
Error: error:0308010C:digital envelope routines::unsupported
Error: error:0308010C:digital envelope routines::unsupported
React Hook "useEffect" is called conditionally. React Hooks must be called in the exact same order in every component render.
React Hook useEffect placed inside a condition
Hook can only be called inside the body of a function component
Hook can only be called inside the body of a function component
Rollup failed to resolve import during build
How to fix "Rollup failed to resolve import" in React