How to fix React Hook useState has been changed from being called conditionally in React

ReactINTERMEDIATEHIGHUpdated Dec 10, 2025· 106 views

This React warning occurs when a useState hook that was previously called unconditionally is now being called inside a conditional statement, loop, or after an early return. React requires hooks to be called in the exact same order on every render to maintain state consistency.

Quick fix

Fixes React Hook useState has been changed from being called conditionally

// ❌ WRONG - useState moved inside condition
function MyComponent({ shouldUseState }) {
  let state, setState;
  
  if (shouldUseState) {
    // This hook is now conditional - was it unconditional before?
    [state, setState] = useState(0);
  }
  
  return <div>{state}</div>;
}

// Check your git history or recent changes to see if this hook
// was previously called unconditionally at the top level.
  1. Identify which hook is being called conditionally
  2. Move all hook calls to the top level of the component
  3. Use conditional logic inside effects or callbacks instead
  4. Refactor complex conditional logic into custom hooks
react — error
// ❌ WRONG - useState moved inside condition
function MyComponent({ shouldUseState }) {
let state, setState;
if (shouldUseState) {
// This hook is now conditional - was it unconditional before?
[state, setState] = useState(0);
}
return <div>{state}</div>;
}
// Check your git history or recent changes to see if this hook
// was previously called unconditionally at the top level.
React Hook useState has been changed from being called conditionally

What this error means

React Hooks rely on being called in a consistent order during every render of a component. When React detects that a hook (like useState) that was previously called unconditionally is now being called conditionally, it throws this warning because the hook order has changed between renders. React maintains an internal "memory cell" for each hook call in a component. The order of these memory cells is determined by the order in which hooks are called during the first render. If a hook moves from being unconditional to conditional (or vice versa), React can't reliably track which state belongs to which hook across renders. This is a specific violation of the "Rules of Hooks" that requires hooks to be called at the top level of React function components, before any early returns, and not inside loops, conditions, or nested functions. The warning helps prevent subtle bugs where state gets mixed up between different hook calls.

Typical symptoms

  • Warning message: "React Hook useState has been changed from being called conditionally"
  • Component state becomes inconsistent or resets unexpectedly
  • State values appear to "jump" between different state variables
  • Component works initially but breaks after certain user interactions
  • Error occurs after refactoring code that moves hook calls into or out of conditions
  • Intermittent bugs that are hard to reproduce consistently
  • State updates don't persist correctly between renders

Common causes

  1. Moving a useState call inside an if/else statement that wasn't conditional before
  2. Adding an early return statement before a hook call that was previously unconditional
  3. Wrapping hook calls in conditional logic based on props or state that changes
  4. Refactoring code that changes the execution path where hooks are called
  5. Converting a component from always rendering to conditionally rendering hooks
  6. Adding loop logic that sometimes skips hook calls
  7. Changing component logic so hooks are called in different branches of conditional statements

How to fix "React Hook useState has been changed from being called conditionally"

1Identify which hook is being called conditionally

Look for useState calls that have moved inside conditional logic. React will typically point to the specific line in the error message:

jsx
// ❌ WRONG - useState moved inside condition
function MyComponent({ shouldUseState }) {
  let state, setState;
  
  if (shouldUseState) {
    // This hook is now conditional - was it unconditional before?
    [state, setState] = useState(0);
  }
  
  return <div>{state}</div>;
}

// Check your git history or recent changes to see if this hook
// was previously called unconditionally at the top level.

Use the React DevTools "Components" tab to inspect the component and see which hooks are being called. The warning should help identify the specific hook causing the issue.

2Move all hook calls to the top level of the component

Ensure all hooks are called unconditionally at the top level, before any early returns:

jsx
// ❌ WRONG - Hook inside condition
function MyComponent({ condition }) {
  if (condition) {
    return <div>Early return</div>;
  }
  
  const [state, setState] = useState(0); // Hook after early return
  return <div>{state}</div>;
}

// ❌ WRONG - Hook in conditional block
function MyComponent({ shouldUse }) {
  if (shouldUse) {
    const [state, setState] = useState(0); // Conditional hook
    return <div>{state}</div>;
  }
  return <div>No state</div>;
}

// ✅ CORRECT - All hooks at top level
function MyComponent({ condition, shouldUse }) {
  // All hooks called unconditionally first
  const [state, setState] = useState(0);
  
  if (condition) {
    return <div>Early return with {state}</div>;
  }
  
  if (shouldUse) {
    return <div>{state}</div>;
  }
  
  return <div>No state display</div>;
}

Even if you don't use the state in some code paths, React needs to call the hook every time to maintain consistent state tracking.

3Use conditional logic inside effects or callbacks instead

If you need conditional behavior based on state or props, put the condition inside useEffect, useCallback, or the component logic, not around the hook call:

jsx
// ❌ WRONG - Conditional hook based on prop
function MyComponent({ enabled }) {
  if (enabled) {
    const [value, setValue] = useState(''); // Conditional
  }
  // ...
}

// ✅ CORRECT - Unconditional hook, conditional logic inside
function MyComponent({ enabled }) {
  const [value, setValue] = useState(''); // Always called
  
  useEffect(() => {
    if (enabled) {
      // Conditional logic inside effect
      setValue('default');
    }
  }, [enabled]);
  
  // Or conditional rendering based on the state
  return enabled ? <div>{value}</div> : <div>Disabled</div>;
}

// ✅ CORRECT - Conditional component composition
function ParentComponent({ showChild }) {
  return showChild ? <ChildWithState /> : <div>No child</div>;
}

function ChildWithState() {
  const [value, setValue] = useState(''); // Unconditional in child
  return <div>{value}</div>;
}

This keeps hook calls consistent while allowing conditional behavior.

4Refactor complex conditional logic into custom hooks

For complex conditional state needs, extract logic into a custom hook that always calls its internal hooks unconditionally:

jsx
// ❌ WRONG - Complex conditional hook logic
function MyComponent({ mode }) {
  if (mode === 'A') {
    const [stateA, setStateA] = useState(null);
    const [dataA, setDataA] = useState([]);
    // ... A logic
  } else if (mode === 'B') {
    const [stateB, setStateB] = useState('');
    const [countB, setCountB] = useState(0);
    // ... B logic
  }
}

// ✅ CORRECT - Custom hooks with unconditional internal calls
function useModeA() {
  const [stateA, setStateA] = useState(null); // Always called
  const [dataA, setDataA] = useState([]);     // Always called
  // ... A logic
  return { stateA, dataA };
}

function useModeB() {
  const [stateB, setStateB] = useState('');   // Always called
  const [countB, setCountB] = useState(0);    // Always called
  // ... B logic
  return { stateB, countB };
}

function MyComponent({ mode }) {
  // Choose which custom hook to use, but hooks inside are unconditional
  const modeLogic = mode === 'A' ? useModeA() : useModeB();
  
  return <div>{/* render based on modeLogic */}</div>;
}

Custom hooks must follow the same rules - all hook calls inside must be unconditional.

5Check for hooks in loops or after conditional returns

Ensure no hooks are inside loops (for, while, map) or after conditional return statements:

jsx
// ❌ WRONG - Hook in loop
function ItemList({ items }) {
  return items.map((item, index) => {
    const [isOpen, setIsOpen] = useState(false); // Hook in map callback
    return (
      <div key={index} onClick={() => setIsOpen(!isOpen)}>
        {isOpen ? item.details : item.name}
      </div>
    );
  });
}

// ✅ CORRECT - Extract to component
function Item({ item }) {
  const [isOpen, setIsOpen] = useState(false); // Hook in component
  return (
    <div onClick={() => setIsOpen(!isOpen)}>
      {isOpen ? item.details : item.name}
    </div>
  );
}

function ItemList({ items }) {
  return items.map((item, index) => (
    <Item key={index} item={item} />
  ));
}

// ❌ WRONG - Hook after conditional return
function MyComponent({ isLoading }) {
  if (isLoading) {
    return <div>Loading...</div>;
  }
  
  const [data, setData] = useState(null); // Hook after return
  // ...
}

// ✅ CORRECT - Hook before any returns
function MyComponent({ isLoading }) {
  const [data, setData] = useState(null); // Hook first
  
  if (isLoading) {
    return <div>Loading...</div>;
  }
  
  // Use data here
  return <div>{data}</div>;
}
6Use the ESLint plugin to prevent future violations

Install and configure eslint-plugin-react-hooks to catch conditional hook calls during development:

bash
npm install --save-dev eslint-plugin-react-hooks

Add to your ESLint configuration:

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

Or in .eslintrc.js:

js
module.exports = {
  plugins: ['react-hooks'],
  rules: {
    'react-hooks/rules-of-hooks': 'error',
    'react-hooks/exhaustive-deps': 'warn'
  }
};

This plugin will underline conditional hook calls as you write code, preventing the "changed from being called conditionally" warning before you even run the code.

7Verify hook order consistency in refactored components

When refactoring components, ensure the hook order remains exactly the same:

jsx
// Before refactoring
function Component() {
  const [name, setName] = useState('');      // Hook 1
  const [count, setCount] = useState(0);     // Hook 2
  const [active, setActive] = useState(false); // Hook 3
  // ...
}

// ❌ WRONG - Hook order changed
function Component({ mode }) {
  if (mode === 'special') {
    const [special, setSpecial] = useState(null); // New hook inserted
  }
  
  const [name, setName] = useState('');      // Now Hook 2 (was 1)
  const [count, setCount] = useState(0);     // Now Hook 3 (was 2)
  const [active, setActive] = useState(false); // Now Hook 4 (was 3)
  // ...
}

// ✅ CORRECT - Maintain original hook order
function Component({ mode }) {
  const [name, setName] = useState('');      // Still Hook 1
  const [count, setCount] = useState(0);     // Still Hook 2
  const [active, setActive] = useState(false); // Still Hook 3
  const [special, setSpecial] = useState(null); // New Hook 4 (at end)
  
  // Conditional logic using the hooks
  if (mode === 'special') {
    // Use special state
  }
  // ...
}

Always add new hooks at the end of the hook sequence to maintain backward compatibility.

Advanced notes

This warning often appears during refactoring or when adding new features to existing components. It's particularly common when:

1. Converting class components to function components - developers may try to conditionally initialize state based on props, which was possible in class constructors but not with hooks.

2. Adding feature flags or A/B testing - wrapping hook calls in conditionals based on feature flags.

3. Implementing lazy loading or code splitting - conditionally importing components that use hooks.

4. Working with render props or higher-order components - hooks may end up being called in different branches of render logic.

Remember that React tracks hooks by their call order index (0, 1, 2, etc.) within each component. If a hook at index 2 becomes conditional and sometimes isn't called, then hook 3 becomes hook 2, and all subsequent state gets misaligned. This is why the error message says "has been changed from being called conditionally" - React remembers the previous render's hook order and detects a change.

In development mode, React performs additional checks and provides more helpful error messages. In production, hook order violations can cause silent bugs where state gets assigned to the wrong variables.

Frequently asked questions

What does "React Hook useState has been changed from being called conditionally" mean?
React Hooks rely on being called in a consistent order during every render of a component. When React detects that a hook (like useState) that was previously called unconditionally is now being called conditionally, it throws this warning because the hook order has changed between renders. React maintains an internal "memory cell" for each hook call in a component.
How do I fix "React Hook useState has been changed from being called conditionally"?
This React warning occurs when a useState hook that was previously called unconditionally is now being called inside a conditional statement, loop, or after an early return. React requires hooks to be called in the exact same order on every render to maintain state consistency.
What causes "React Hook useState has been changed from being called conditionally"?
Moving a useState call inside an if/else statement that wasn't conditional before Adding an early return statement before a hook call that was previously unconditional Wrapping hook calls in conditional logic based on props or state that changes
Is the "React Hook useState has been changed from being called conditionally" 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