This React warning occurs when you attempt to update a component's state from within the render function of another component, which violates React's rendering rules and can cause infinite loops or inconsistent UI states.
This warning is React's way of preventing state updates during the render phase of another component. React has a strict rendering cycle: during render, components should only compute their output based on props and state, not modify other components' state. When Component A is rendering, it should not trigger a state update in Component B, as this creates a circular dependency that can lead to infinite re-renders, inconsistent UI states, or performance issues. React enforces this rule because state updates during render can cause the component tree to become unstable. Each component render should be a pure function of its props and state - if Component A's render causes Component B to update, and Component B's render causes Component A to update, you get an infinite loop. This warning helps catch these problematic patterns before they cause runtime errors or performance degradation. Understanding this error is crucial for writing predictable React applications that follow the unidirectional data flow pattern.
Instead of updating state directly in the component body, use useEffect to schedule updates after render:
// ❌ WRONG - State update during render
function ParentComponent() {
const [count, setCount] = useState(0);
// This triggers during ParentComponent's render
setCount(1); // Warning!
return <ChildComponent />;
}
// ✅ CORRECT - Use useEffect
function ParentComponent() {
const [count, setCount] = useState(0);
useEffect(() => {
// This runs AFTER render
setCount(1);
}, []);
return <ChildComponent />;
}useEffect runs after the component renders, which is the correct time to trigger state updates.
For state updates triggered by user actions, use event handlers instead of calling them during render:
// ❌ WRONG - Calling update function during render
function ParentComponent() {
const [data, setData] = useState(null);
// fetchData triggers setData during render
fetchData().then(setData); // Warning!
return <ChildComponent />;
}
// ✅ CORRECT - Use useEffect or event handlers
function ParentComponent() {
const [data, setData] = useState(null);
useEffect(() => {
fetchData().then(setData);
}, []);
const handleClick = () => {
fetchData().then(setData);
};
return (
<div>
<ChildComponent />
<button onClick={handleClick}>Load Data</button>
</div>
);
}State updates should be triggered by events (clicks, API responses, timers) not during render.
When parent components need to update child state, use props and callbacks instead of direct state manipulation:
// ❌ WRONG - Parent updating child state during render
function ParentComponent() {
const childRef = useRef();
// This would update child state during parent render
if (childRef.current) {
childRef.current.updateState(); // Warning!
}
return <ChildComponent ref={childRef} />;
}
// ✅ CORRECT - Use props and callbacks
function ParentComponent() {
const [childData, setChildData] = useState(null);
const updateChild = (newData) => {
setChildData(newData);
};
return (
<ChildComponent
data={childData}
onUpdate={updateChild}
/>
);
}
function ChildComponent({ data, onUpdate }) {
// Child controls its own updates via onUpdate callback
const handleClick = () => {
onUpdate('new data');
};
return <button onClick={handleClick}>Update</button>;
}Follow React's unidirectional data flow: props down, events up.
When using React Context, avoid updating context values from within consumer components during render:
// ❌ WRONG - Updating context during render
function MyComponent() {
const { setTheme } = useContext(ThemeContext);
// This updates context during render
setTheme('dark'); // Warning!
return <div>Content</div>;
}
// ✅ CORRECT - Update context in useEffect or event handlers
function MyComponent() {
const { theme, setTheme } = useContext(ThemeContext);
useEffect(() => {
// Update context after render if needed
if (someCondition) {
setTheme('dark');
}
}, [someCondition, setTheme]);
const handleToggle = () => {
setTheme(theme === 'light' ? 'dark' : 'light');
};
return (
<div>
<button onClick={handleToggle}>Toggle Theme</button>
</div>
);
}Context updates should be triggered by user actions or effects, not during component render.
Wrap callback functions in useCallback to prevent them from being recreated on every render, which can trigger unintended state updates:
// ❌ WRONG - New function on every render
function ParentComponent() {
const [count, setCount] = useState(0);
const handleUpdate = () => {
setCount(count + 1);
};
// handleUpdate is new on every render
// If ChildComponent calls it during Parent's render, warning occurs
return <ChildComponent onUpdate={handleUpdate} />;
}
// ✅ CORRECT - Memoize callbacks
function ParentComponent() {
const [count, setCount] = useState(0);
const handleUpdate = useCallback(() => {
setCount(prev => prev + 1);
}, []); // Empty dependency array
return <ChildComponent onUpdate={handleUpdate} />;
}
// Even better - use functional updates
const handleUpdate = useCallback(() => {
setCount(prev => prev + 1);
}, []);Memoized callbacks are more predictable and prevent unnecessary re-renders.
Ensure API calls, calculations, or other side effects don't trigger state updates synchronously:
// ❌ WRONG - Synchronous state update during render
function DataComponent() {
const [data, setData] = useState(null);
// This runs during render and updates state
const result = computeExpensiveValue();
setData(result); // Warning!
return <div>{data}</div>;
}
// ✅ CORRECT - Use useEffect or useMemo
function DataComponent() {
const [data, setData] = useState(null);
const expensiveValue = useMemo(() => {
return computeExpensiveValue();
}, [dependencies]);
useEffect(() => {
setData(expensiveValue);
}, [expensiveValue]);
return <div>{data}</div>;
}
// ✅ CORRECT - Lazy initialization
function DataComponent() {
const [data, setData] = useState(() => {
// This only runs once during initial render
return computeExpensiveValue();
});
return <div>{data}</div>;
}Use useMemo for expensive calculations and useEffect for side effects.
Wrap your app in React.StrictMode to get additional warnings about unsafe lifecycle methods and render phase updates:
// In your main app file (index.jsx/App.jsx)
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
// Or in Next.js, update next.config.js
export default {
reactStrictMode: true,
};Strict Mode helps identify problematic patterns by:
1. Double-invoking render methods to detect side effects
2. Warning about deprecated lifecycle methods
3. Detecting unexpected side effects in render
4. Identifying components with unsafe side effects
Run your app with Strict Mode enabled during development to catch these warnings early.
This warning is particularly important in Concurrent React (React 18+), where components can be rendered multiple times before committing to the DOM. In concurrent rendering, side effects during render can cause even more unpredictable behavior because React might throw away a render pass and start over.
For library authors: Be careful when exposing imperative APIs (refs with methods) that could be called during render. Consider using callbacks or events instead of direct method calls.
In server components (React 18+ Server Components), this pattern is even more critical because server components cannot have state or effects. Any attempt to update state during server component render will fail at build time or runtime.
Performance consideration: State updates during render not only cause warnings but also degrade performance. Each state update triggers a re-render, and if that happens during another component's render, you get cascading re-renders that React must reconcile.
React Hook useCallback has a missing dependency: 'variable'. Either include it or remove the dependency array react-hooks/exhaustive-deps
React Hook useCallback has a missing dependency
Cannot use private fields in class components without TS support
Cannot use private fields in class components without TS support
Cannot destructure property 'xxx' of 'undefined'
Cannot destructure property of undefined when accessing props
useNavigate() may be used only in the context of a <Router> component.
useNavigate() may be used only in the context of a Router component
Cannot find module or its corresponding type declarations
How to fix "Cannot find module or type declarations" in Vite