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.
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.
Look for useState calls that have moved inside conditional logic. React will typically point to the specific line in the error message:
// ❌ 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.
Ensure all hooks are called unconditionally at the top level, before any early returns:
// ❌ 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.
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:
// ❌ 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.
For complex conditional state needs, extract logic into a custom hook that always calls its internal hooks unconditionally:
// ❌ 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.
Ensure no hooks are inside loops (for, while, map) or after conditional return statements:
// ❌ 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>;
}Install and configure eslint-plugin-react-hooks to catch conditional hook calls during development:
npm install --save-dev eslint-plugin-react-hooksAdd to your ESLint configuration:
{
"plugins": ["react-hooks"],
"rules": {
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn"
}
}Or in .eslintrc.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.
When refactoring components, ensure the hook order remains exactly the same:
// 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.
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.
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