"Cannot update a component while rendering."
Three fixes, one root cause.
You called setState inside render — inside the component body, not inside an event handler. React's warning is precise: renders must be pure. This page shows the three causes, the three fixes, and the underlying pattern that eliminates the bug entirely.
Short answer: Remove the setState call from render. If you're syncing state to props, don't store derived state — compute it inline or with useMemo. If you're calling setState in response to a prop change, use useEffect (still not ideal) or the key prop to remount. If you're calling setState in a child during a parent's render, move the call to an event handler or a callback. The fix always removes the setState from the render phase.
✅ Solution 1 — Don't store derived state
The most common cause. Compute, don't store.
If a value can be computed from props or other state, it doesn't belong in useState. Storing it forces you to keep it in sync — usually via useEffect or setState during render. Both are unnecessary. Compute the value directly in the render function; the compiler optimizes the rest.
import { useState } from 'react'; // ─── BAD: derived state in useState ────────── function BadFullName() { const [first, setFirst] = useState('Alice'); const [last, setLast] = useState('Smith'); const [full, setFull] = useState(first + ' ' + last); // ⚠️ derived // ❌ Calling setState during render setFull(first + ' ' + last); // ⚠️ Warning: Cannot update a component while rendering return{full}
; } // ─── GOOD: compute during render ──────────── function GoodFullName() { const [first, setFirst] = useState('Alice'); const [last, setLast] = useState('Smith'); // ✅ Computed every render — always correct, no state const full = first + ' ' + last; return (setFirst(e.target.value)} /> setLast(e.target.value)} />); } // ─── GOOD: useMemo for expensive derivations ─ function ExpensiveDerived({ items }: { items: number[] }) { // Only recompute when items changes const total = useMemo( () => items.reduce((sum, n) => sum + n, 0), [items] ); return{full}
Total: {total}
; } // ─── Rule ──────────────────────────────────── // // If X can be computed from props or other state: // const X = compute(props, otherState); // // If that computation is expensive: // const X = useMemo(() => compute(props), [props]); // // Never: // const [X, setX] = useState(...); // setX(...) // in render — warning // useEffect(() => setX(...), [props]); // extra render, still wrong console.log(BadFullName, GoodFullName, ExpensiveDerived);
import { useState } from 'react'; function BadFullName() { const [first, setFirst] = useState('Alice'); const [last, setLast] = useState('Smith'); const [full, setFull] = useState(first + ' ' + last); setFull(first + ' ' + last); return React.createElement('p', null, full); } function GoodFullName() { const [first, setFirst] = useState('Alice'); const [last, setLast] = useState('Smith'); const full = first + ' ' + last; return React.createElement('div', null, React.createElement('input', { value: first, onChange: e => setFirst(e.target.value) }), React.createElement('input', { value: last, onChange: e => setLast(e.target.value) }), React.createElement('p', null, full) ); } function ExpensiveDerived({ items }) { const total = useMemo(() => items.reduce((sum, n) => sum + n, 0), [items]); return React.createElement('p', null, 'Total: ', total); } console.log(BadFullName, GoodFullName, ExpensiveDerived);
Compute during render
If a value derives from other state, compute it in the render function. No state, no sync, no warning.
useMemo for expensive
If the computation is slow, wrap in useMemo with correct dependencies. Only recomputes when deps change.
No useEffect for derivation
Even useEffect(() => setX(...), [props]) is wrong — it triggers an extra render. Compute instead.
The rule
State is for data that changes over time due to user interaction or external events. Everything else is computed.
The most common React mistake is storing too much in state. Every useState is a source of truth that can drift out of sync. If a value can be derived from other values, it should be. The bug pattern: you have props and state that disagree, and you add more state or effects to fix the disagreement. The right answer is usually to remove the derived state entirely. If you find yourself writing useEffect(() => setX(...), [something]), stop — you almost never need it. Compute the value in the render function.
✅ Solution 2 — Move setState to an event handler or effect
When the state genuinely responds to something.
Sometimes you need to update state in response to a user action or external event. That's what setState is for — but only inside event handlers, useEffect, or callbacks. Never inside render. If your code was calling setState during render to respond to a prop change, the correct fix is to move it to an event handler or use a useEffect.
import { useState, useEffect } from 'react'; interface User { id: string; name: string; email: string; } // ─── BAD: setting state during render ──────── function BadUserDisplay({ userId }: { userId: string }) { const [user, setUser] = useStatenull>(null); // ❌ Called during render if (userId !== user?.id) { setUser(fetchUserSync(userId)); } return {user?.name ?? 'Loading...'}
; } // ─── GOOD: use useEffect for external data ─── function GoodUserDisplay({ userId }: { userId: string }) { const [user, setUser] = useStatenull>(null); useEffect(() => { let cancelled = false; fetch(/api/users/${userId}`) .then(r => r.json()) .then(data => { if (!cancelled) setUser(data); }); return () => { cancelled = true; }; }, [userId]); return {user?.name ?? 'Loading...'}
; } // ─── GOOD: set state in an event handler ───── function Counter() { const [count, setCount] = useState(0); // ✅ User clicks the button → setCount runs in the event function handleClick() { setCount(c => c + 1); } return ( ); } // ─── GOOD: use a key to remount instead of syncing // If a component should reset its internal state when props // change, use key — it forces a fresh mount. function UserForm({ userId }: { userId: string }) { const [draft, setDraft] = useState(''); return (setDraft(e.target.value)} />); } function App({ userId }: { userId: string }) { // When userId changes, UserForm remounts with fresh state return; } function fetchUserSync(id: string): User { return { id, name: 'Alice', email: 'a@x.com' }; } console.log(BadUserDisplay, GoodUserDisplay, Counter, UserForm, App);
import { useState, useEffect } from 'react'; function BadUserDisplay({ userId }) { const [user, setUser] = useState(null); if (userId !== user?.id) { setUser(fetchUserSync(userId)); } return React.createElement('p', null, user?.name ?? 'Loading...'); } function GoodUserDisplay({ userId }) { const [user, setUser] = useState(null); useEffect(() => { let cancelled = false; fetch(/api/users/${userId}`) .then(r => r.json()) .then(data => { if (!cancelled) setUser(data); }); return () => { cancelled = true; }; }, [userId]); return React.createElement('p', null, user?.name ?? 'Loading...'); } function Counter() { const [count, setCount] = useState(0); function handleClick() { setCount(c => c + 1); } return React.createElement('button', { onClick: handleClick }, 'Count: ', count); } function UserForm({ userId }) { const [draft, setDraft] = useState(''); return React.createElement('div', null, React.createElement('input', { value: draft, onChange: e => setDraft(e.target.value) }) ); } function App({ userId }) { return React.createElement(UserForm, { key: userId, userId }); } function fetchUserSync(id) { return { id, name: 'Alice', email: 'a@x.com' }; } console.log(BadUserDisplay, GoodUserDisplay, Counter, UserForm, App);
Event handler
onClick, onChange, onSubmit — these call setState. That's fine. Users trigger, state updates.
useEffect for external
Fetching, subscriptions, timers. Set state inside the effect, not during render. Cleanup cancels pending updates.
key for resets
If a component should reset when props change, pass a key. React remounts with fresh state — no sync needed.
Never in render
The render function is pure. No setState, no side effects, no DOM manipulation. Just compute the JSX.
✅ Solution 3 — Move setState out of the child's render
When a child component triggers a parent update during its own render.
Another variant: a child component calls setState on the parent — or on a shared store — during its own render. React warns because the parent hasn't finished rendering yet. The fix: move the update to a callback that runs after render (event handler, effect) — or lift the state higher so the update is local.
import { useState } from 'react'; // ─── BAD: child calls parent setState during render function BadChild({ onMount }: { onMount: () => void }) { // ❌ Called during render, before BadChild finishes onMount(); returnChild
; } function BadParent() { const [mounted, setMounted] = useState(false); return (); } // ─── GOOD: use useEffect in the child ──────── function GoodChild({ onMount }: { onMount: () => void }) { useEffect(() => { // ✅ Runs after the child has mounted and rendered onMount(); }, []); returnsetMounted(true)} /> {/* ⚠️ Cannot update a component while rendering */} {mounted ? 'mounted' : 'mounting'}
Child
; } function GoodParent() { const [mounted, setMounted] = useState(false); return (); } // ─── ALTERNATIVE: lift state up ────────────── // If the parent needs to know something about the child, // the parent usually owns the state. Pass it down as props. function LiftedChild({ isActive }: { isActive: boolean }) { returnsetMounted(true)} /> {mounted ? 'mounted' : 'mounting'}
{isActive ? 'Active' : 'Inactive'}
; } function LiftedParent() { const [isActive, setIsActive] = useState(false); return (); } // ─── The rules ─────────────────────────────── // // 1. Child never calls parent's setState during render. // 2. If a child needs to communicate something, // it's usually a callback called from an event, // effect, or a lifted state that lives in the parent. // 3. If you want the parent to "know" something, // the parent probably owns that state. import { useEffect } from 'react'; console.log(BadParent, GoodParent, LiftedParent);
import { useState, useEffect } from 'react'; function BadChild({ onMount }) { onMount(); return React.createElement('p', null, 'Child'); } function BadParent() { const [mounted, setMounted] = useState(false); return React.createElement('div', null, React.createElement(BadChild, { onMount: () => setMounted(true) }), React.createElement('p', null, mounted ? 'mounted' : 'mounting') ); } function GoodChild({ onMount }) { useEffect(() => { onMount(); }, []); return React.createElement('p', null, 'Child'); } function GoodParent() { const [mounted, setMounted] = useState(false); return React.createElement('div', null, React.createElement(GoodChild, { onMount: () => setMounted(true) }), React.createElement('p', null, mounted ? 'mounted' : 'mounting') ); } function LiftedChild({ isActive }) { return React.createElement('p', null, isActive ? 'Active' : 'Inactive'); } function LiftedParent() { const [isActive, setIsActive] = useState(false); return React.createElement('div', null, React.createElement(LiftedChild, { isActive }), React.createElement('button', { onClick: () => setIsActive(true) }, 'Activate') ); } console.log(BadParent, GoodParent, LiftedParent);
Child → parent updates
If a child needs to inform the parent, use a callback called from an event or effect. Never call it during render.
useEffect for lifecycle
onMount runs after render via useEffect(..., []). The parent's state updates after render finishes.
Lift state up
If the parent truly owns the state, don't ask the child to set it. The parent sets it in the event that triggered the change.
Data flows down
The React mental model: props flow down, callbacks flow up. A child doesn't "set" parent state — it calls a callback the parent provided.
This warning is a real bug, not a style nit. React 18+ makes calling setState during render an error because it can produce inconsistent UI — the parent might render before the child's update lands, or the update might be discarded in concurrent mode. Fix the actual data flow. Don't wrap it in setTimeout or queueMicrotask to silence the warning — that just moves the bug to a race condition that's harder to debug.
⚠️ Common mistakes
The patterns that trigger this warning.
function Component() { setX(...); return ...; } — warning. Fix: move to event handler or useEffect.
if (props.x !== state) setState(props.x) during render. Fix: don't store props in state. Compute or use key.
useEffect to "fix" ituseEffect(() => setX(props.x), [props.x]) — no warning, but extra render + potential stale state. Fix: derive in render.
setState in a callback during render{items.map(i => { if (i.bad) setX(...); return ...; })} — warning. Fix: filter in render, or dispatch in an effect.
setState in a memo selectorReact 18 concurrent mode is strict about this. Fix: derive in the component, not in selectors that run during render.
function Child({ onMount }) { onMount(); return ...; } — warning. Fix: useEffect(() => onMount(), []).
setTimeoutsetTimeout(() => setX(...), 0) inside render — moves the bug. Fix: restructure the state.
The warning existed in React 16-17 but was easy to ignore. React 18+ is stricter. Fix: it was always a bug.
❓ Frequently asked
What does "Cannot update a component while rendering" mean in React?
It means you called setState during a component's render phase — inside the component function, not inside an event handler or effect. React renders are supposed to be pure: same props, same JSX, no side effects. Calling setState during render schedules an update to another component (or the same one), which triggers a re-render during a render.
Why did this error start appearing after I upgraded React?
React 18+ is stricter about calling setState during render. The warning existed in React 16-17 but was easier to ignore. React 18 added concurrency features that make the warning a hard error in some cases. The fix is the same: don't call setState during render.
How do I fix it if I need to derive state from props?
Don't store derived state in useState. Compute it inline: instead of const [full, setFull] = useState(first + ' ' + last), write const full = first + ' ' + last. If computation is expensive, wrap in useMemo. If you must sync, use the key prop to remount the component when the input changes.
What is the difference between calling setState during render vs inside useEffect?
setState during render happens synchronously as React renders — it interrupts the render with a new render, which is what causes the warning. setState inside useEffect runs after the render completes, so React schedules another render normally. Effect-based setState is also not ideal but it's not a warning.