How to fix React Hook "useState" is called conditionally. React Hooks must be called in the exact same order in every component render. in React

ReactBEGINNERMEDIUMUpdated Dec 9, 2025· 104 views

This ESLint error occurs when useState is called inside a conditional statement, loop, or after an early return. React requires hooks to be called in the same order on every render to maintain state consistency.

Quick fix

Fixes rules-of-hooks

// ❌ WRONG - useState inside conditional
function MyComponent({ isLoggedIn }) {
  if (isLoggedIn) {
    const [user, setUser] = useState(null); // Error!
  }
  // ...
}

// ✅ CORRECT - useState at top level
function MyComponent({ isLoggedIn }) {
  const [user, setUser] = useState(null);

  if (isLoggedIn) {
    // Use the state here
  }
  // ...
}
  1. Move all hook calls to the top of your component
  2. Move conditional logic inside the hook or JSX
  3. Extract conditional components into separate child components
  4. Use null or default values instead of conditional hook calls
react — error
// ❌ WRONG - useState inside conditional
function MyComponent({ isLoggedIn }) {
if (isLoggedIn) {
const [user, setUser] = useState(null); // Error!
}
// ...
}
// ✅ CORRECT - useState at top level
function MyComponent({ isLoggedIn }) {
const [user, setUser] = useState(null);
if (isLoggedIn) {
// Use the state here
}
// ...
}
React Hook "useState" is called conditionally. React Hooks must be called in the exact same order in every component render.

What this error means

This error is reported by the eslint-plugin-react-hooks when it detects a useState hook being called conditionally. React hooks rely on call order to associate state with specific hook calls across renders. When you call useState inside an if statement, loop, or after an early return, the hook might not execute on every render, breaking React's internal tracking mechanism. React uses a linked list internally to track hooks in the order they're called. If the order changes between renders because a conditional statement prevents a hook from executing, React can't match the stored state to the correct hook call, leading to bugs or crashes. The eslint-plugin-react-hooks enforces the Rules of Hooks to prevent these issues at development time, catching violations before they cause runtime errors.

Typical symptoms

  • ESLint error appears in your IDE or terminal during development
  • Error message specifically mentions "called conditionally" for useState
  • The hook call is inside an if/else block, switch statement, or loop
  • Hook is called after an early return statement in the component
  • Build or linting process fails with rules-of-hooks violation

Common causes

  1. Calling useState inside an if, else, or switch conditional block
  2. Placing useState call after an early return statement
  3. Using useState within a loop (for, while, forEach, map)
  4. Nesting useState inside a callback or nested function
  5. Conditionally rendering logic that includes hook calls
  6. Trying to use hooks only when certain props or state conditions are met

How to fix "React Hook "useState" is called conditionally. React Hooks must be called in the exact same order in every component render."

1Move all hook calls to the top of your component

Always call hooks at the top level of your function component, before any conditional logic or early returns:

jsx
// ❌ WRONG - useState inside conditional
function MyComponent({ isLoggedIn }) {
  if (isLoggedIn) {
    const [user, setUser] = useState(null); // Error!
  }
  // ...
}

// ✅ CORRECT - useState at top level
function MyComponent({ isLoggedIn }) {
  const [user, setUser] = useState(null);

  if (isLoggedIn) {
    // Use the state here
  }
  // ...
}

This ensures hooks are called in the same order every render.

2Move conditional logic inside the hook or JSX

Instead of conditionally calling the hook, always call it and conditionally use its value:

jsx
// ❌ WRONG
function UserProfile({ showGreeting }) {
  if (showGreeting) {
    const [greeting, setGreeting] = useState('Hello'); // Error!
  }
  return <div>Profile</div>;
}

// ✅ CORRECT - Hook always called, usage is conditional
function UserProfile({ showGreeting }) {
  const [greeting, setGreeting] = useState('Hello');

  return (
    <div>
      {showGreeting && <h1>{greeting}</h1>}
      <div>Profile</div>
    </div>
  );
}
3Extract conditional components into separate child components

If you need hooks to run only in certain conditions, create a separate component:

jsx
// ❌ WRONG
function Dashboard({ userType }) {
  if (userType === 'admin') {
    const [adminData, setAdminData] = useState([]); // Error!
  }
  return <div>Dashboard</div>;
}

// ✅ CORRECT - Separate component
function AdminPanel() {
  const [adminData, setAdminData] = useState([]);
  // Admin-specific logic
  return <div>Admin Panel: {adminData.length} items</div>;
}

function Dashboard({ userType }) {
  return (
    <div>
      <h1>Dashboard</h1>
      {userType === 'admin' && <AdminPanel />}
    </div>
  );
}

This pattern keeps hooks at the top level of their respective components.

4Use null or default values instead of conditional hook calls

Initialize state with appropriate defaults and update conditionally:

jsx
// ❌ WRONG
function DataLoader({ shouldLoad }) {
  if (shouldLoad) {
    const [data, setData] = useState(null); // Error!
    const [loading, setLoading] = useState(false); // Error!
  }
  return null;
}

// ✅ CORRECT - Always call hooks with appropriate defaults
function DataLoader({ shouldLoad }) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    if (!shouldLoad) return; // Conditional logic inside useEffect

    setLoading(true);
    fetchData().then(result => {
      setData(result);
      setLoading(false);
    });
  }, [shouldLoad]);

  if (!shouldLoad) return null;
  if (loading) return <div>Loading...</div>;
  return <div>{data}</div>;
}
5Fix hooks called after early returns

Ensure all hook calls happen before any return statements:

jsx
// ❌ WRONG - Hook after early return
function ErrorBoundary({ error, children }) {
  if (error) {
    return <div>Error: {error.message}</div>;
  }

  const [retryCount, setRetryCount] = useState(0); // Error! Never reached if error exists
  return children;
}

// ✅ CORRECT - All hooks before any returns
function ErrorBoundary({ error, children }) {
  const [retryCount, setRetryCount] = useState(0);

  if (error) {
    return (
      <div>
        Error: {error.message}
        <button onClick={() => setRetryCount(c => c + 1)}>
          Retry ({retryCount})
        </button>
      </div>
    );
  }

  return children;
}

Advanced notes

Understanding React's Hook State Machine

React maintains hooks in a linked list indexed by call order. Each render, React traverses this list in sequence. If a hook is skipped due to a conditional, the indices shift, causing React to associate state with the wrong hook calls.

ESLint Configuration

The rules-of-hooks rule is part of eslint-plugin-react-hooks. Ensure it's enabled in your ESLint config:

json
{
  "plugins": ["react-hooks"],
  "rules": {
    "react-hooks/rules-of-hooks": "error"
  }
}

Custom Hooks and Conditionals

Custom hooks must also follow these rules. If you need conditional logic, wrap it in a custom hook that always calls its internal hooks:

jsx
// ✅ Custom hook that always calls useState
function useConditionalState(condition, initialValue) {
  const [state, setState] = useState(initialValue);
  return condition ? [state, setState] : [null, () => {}];
}

TypeScript Considerations

When using TypeScript with conditional rendering patterns, ensure type guards don't introduce hook call order issues. Always call hooks before type narrowing logic.

React Compiler Future

The upcoming React Compiler may optimize some of these patterns, but the fundamental rule of consistent hook call order will remain a requirement for the foreseeable future.

Frequently asked questions

What does "rules-of-hooks" mean?
This error is reported by the eslint-plugin-react-hooks when it detects a useState hook being called conditionally. React hooks rely on call order to associate state with specific hook calls across renders. When you call useState inside an if statement, loop, or after an early return, the hook might not execute on every render, breaking React's internal tracking mechanism.
How do I fix "rules-of-hooks"?
This ESLint error occurs when useState is called inside a conditional statement, loop, or after an early return. React requires hooks to be called in the same order on every render to maintain state consistency.
What causes "rules-of-hooks"?
Calling useState inside an if, else, or switch conditional block Placing useState call after an early return statement Using useState within a loop (for, while, forEach, map)
Is the "rules-of-hooks" error serious?
It is a medium-severity error — more of a blocker than a risk. The steps above resolve it.

Official resources & further reading