React prints this warning when one component changes another component’s state while it is rendering. Depending on your React version the text is either “Cannot update a component (Parent) while rendering a different component (Child)” or the older “Cannot update a component from inside the function body of a different component”. Both mean the same thing: a state setter was called during render instead of in an event handler or an effect. This guide reproduces the warning, shows the three ways people cause it, and gives the fix for each, including the one case where calling a setter during render is actually fine.
Every example was built and run with React 19.3.0 in a Vite project, and the warning text in the screenshot is React’s own, captured in the browser. Reference: setState in render on react.dev.
What the warning looks like
Here is the smallest component that triggers it: a child that calls its parent’s setter in the render body. The warning is printed to the console, and this example also shows it on the page so you can read it in full:
import { useState, useEffect } from "react";
// this only exists so the warning can be shown on the page: it has to run
// before React renders, because the warning happens during the first render
const warnings = [];
const originalError = console.error;
console.error = (template, ...rest) => {
warnings.push(String(template).replace(/%s/g, () => String(rest.shift()))); // React sends "%s" placeholders
originalError(template, ...rest);
};
function useCapturedWarning() {
const [warning, setWarning] = useState("");
useEffect(() => { setWarning(warnings[0] ?? ""); }, []);
return warning;
}
function Child({ setTotal }) {
setTotal(42); // <-- updating the PARENT while this child renders
return <p>child rendered</p>;
}
Child.displayName = "Child";
function Parent() {
const [total, setTotal] = useState(0);
return (
<>
<p>total: {total}</p>
<Child setTotal={setTotal} />
</>
);
}
Parent.displayName = "Parent";
export default function App() {
const warning = useCapturedWarning();
return (
<div style={{ fontFamily: "system-ui", padding: 16 }}>
<Parent />
<pre style={{ background: "#fff8e6", border: "1px solid #f0d08a", borderRadius: 6,
padding: 12, whiteSpace: "pre-wrap", color: "#5a4300" }}>{warning || "no warning yet"}</pre>
</div>
);
}
Output:
[error] Cannot update a component (`%s`) while rendering a different component (`%s`). To locate the bad setState() call inside `%s`, follow the stack trace as described in https://react.dev/link/setstate-in-render
Read the two names carefully, because they tell you exactly where to look: the first is the component whose state is changing, the second is the component whose render did it. The link in the message goes to React’s own explanation.
Why React complains
Rendering is supposed to be a calculation: given props and state, return what the UI should look like, and change nothing else. When a component sets another component’s state during that calculation, React is already part-way through the tree, so it has to throw away the work and start again. If the setter runs on every render, it never stops, and the warning becomes Too many re-renders instead.
Cause 1: calling the handler instead of passing it
This is the most common version by a distance, and it usually appears with a state setter as the handler. onClick={setCount(count + 1)} calls the function while the JSX is being built. Pass a function instead, so React can call it when the click happens, as covered in passing a function to a child component:
import { useState } from "react";
export default function App() {
const [count, setCount] = useState(0);
// WRONG: setCount(count + 1) runs while App renders, not when the button is clicked
// <button onClick={setCount(count + 1)}>Add</button>
return (
<div style={{ fontFamily: "system-ui", padding: 16 }}>
<p id="count">count: {count}</p>
{/* RIGHT: pass a function, so React calls it on the click */}
<button id="add" onClick={() => setCount(count + 1)}
style={{ padding: "6px 12px", marginRight: 8, borderRadius: 6,
border: "1px solid #0b6bcb", background: "#0b6bcb", color: "#fff", cursor: "pointer" }}>
Add one
</button>
{/* also right: a reference to a function that takes no arguments */}
<button id="reset" onClick={() => setCount(0)}
style={{ padding: "6px 12px", borderRadius: 6, border: "1px solid #0b6bcb",
background: "#fff", color: "#0b6bcb", cursor: "pointer" }}>
Reset
</button>
</div>
);
}
Cause 2: a value that should not be state at all
The second cause is storing something in state that could simply be calculated. A filtered list and its total do not need their own state or an effect to keep them in sync: work them out during render, from the state you already have. Fewer moving parts, and the warning cannot happen:
import { useState } from "react";
const orders = [
{ id: "ORD-1001", city: "Austin", total: 249.99 },
{ id: "ORD-1002", city: "Denver", total: 89.5 },
{ id: "ORD-1003", city: "Austin", total: 430 },
];
export default function App() {
const [city, setCity] = useState("Austin");
// no second piece of state, no effect: just work it out while rendering
const shown = orders.filter(order => order.city === city);
const total = shown.reduce((sum, order) => sum + order.total, 0);
console.log(`${city}: ${shown.length} orders, $${total.toFixed(2)}`);
return (
<div style={{ fontFamily: "system-ui", padding: 16 }}>
{["Austin", "Denver"].map(name => (
<button key={name} id={`city-${name}`} onClick={() => setCity(name)}
style={{ marginRight: 8, padding: "6px 12px", borderRadius: 6, cursor: "pointer",
border: "1px solid #0b6bcb", background: city === name ? "#0b6bcb" : "#fff",
color: city === name ? "#fff" : "#0b6bcb" }}>
{name}
</button>
))}
<p id="summary">{shown.length} orders, ${total.toFixed(2)}</p>
</div>
);
}
Console output after clicking Denver:
Austin: 2 orders, $679.99
Denver: 1 orders, $89.50
Cause 3: a genuine side effect, in the wrong place
Sometimes the update really does have to happen: a default selection, a parent that must know about a child’s measured size, a sync with something outside React. Those are side effects, so they belong in useEffect, which runs after the render is committed rather than during it:
import { useState, useEffect } from "react";
const cities = ["Austin", "Denver", "Seattle"];
function CityPicker({ onSelect, selected }) {
// a default selection is a side effect, so it belongs in an effect, not in render
useEffect(() => {
if (!selected) {
console.log("no city chosen yet, defaulting to", cities[0]);
onSelect(cities[0]);
}
}, [selected, onSelect]);
return <p>selected: {selected ?? "nothing"}</p>;
}
export default function App() {
const [city, setCity] = useState(null);
console.log("App rendered with:", city);
return (
<div style={{ fontFamily: "system-ui", padding: 16 }}>
<CityPicker selected={city} onSelect={setCity} />
</div>
);
}
Console output:
App rendered with: null
no city chosen yet, defaulting to Austin
App rendered with: Austin
Use this sparingly. An effect that only copies one piece of state into another is usually the smell described in cause 2, and it costs an extra render every time. If a child needs to tell a parent something, a callback prop is better than an effect, and preventing unnecessary child re-renders covers the performance side.
The exception: updating your own component during render
Calling your own setter during your own render does not produce this warning. React discards the in-progress render and immediately runs the component again with the new value. It is a documented escape hatch for adjusting state when a prop changes, and the only rule is that it has to settle:
import { useState } from "react";
export default function App() {
const [items, setItems] = useState(["Austin", "Denver"]);
const [count, setCount] = useState(0);
// updating THIS component during its own render is allowed, as long as it stops.
// React throws the render away and runs it again with the new value.
if (count !== items.length) {
console.log("adjusting count from", count, "to", items.length);
setCount(items.length);
}
console.log("rendered with count", count);
return <p style={{ fontFamily: "system-ui", padding: 16 }}>{count} items</p>;
}
Console output:
adjusting count from 0 to 2
rendered with count 0
rendered with count 2
Notice there is no warning, and the component rendered twice. Guard it with a condition that becomes false, as above, or you will hit the re-render limit.
| What you wrote | What happens | Fix |
|---|---|---|
onClick={setOpen(true)} | Runs during render | onClick={() => setOpen(true)} |
Child calls props.setX(...) in its body | Warning, then a loop | Call it in a handler or an effect |
setTotal(...) to mirror a prop | Extra render, easy to desync | Calculate the value during render |
| Parent setter inside a child’s render | Warning naming both components | Lift the logic or use a callback |
| Own setter during own render, guarded | Allowed, one extra render | Nothing to fix |
More React troubleshooting guides:
- React component not rendering
- Prevent a child component re-rendering
- React hooks in class components
- Error boundaries in function components
- State updates on unmounted components
Frequently asked questions
Why does React say cannot update a component while rendering a different component?
A state setter belonging to one component was called during another component’s render. Move it into an event handler or a useEffect.
What does “from inside the function body of a different component” mean?
It is the older wording of the same warning. The setter ran in the component’s function body, which is its render, rather than in a handler or effect.
Why does onClick={setValue(value)} break?
Because it calls the setter while the JSX is built. Write onClick={() => setValue(value)} so React calls it on the click.
Can I call a useState setter inside a component body?
Only for the component’s own state, and only guarded so it stops. Calling another component’s setter during render is what triggers the warning.
Should I use useEffect to fix it?
Only when the update is a real side effect. If the value can be calculated from existing state and props, calculate it during render instead.
Is it an error or just a warning?
A warning, and it appears only in development builds. Ignore it and it usually becomes the Too many re-renders error.
Can a child component update parent state in React?
Yes, through a callback prop, but it has to happen in an event handler or an effect, never while the child is rendering.
Bijay Kumar is a 13-time Microsoft MVP with more than 18 years in software development, and the founder of Python Guides and TSinfo Technologies. He started out building .NET and SharePoint solutions at HP, TCS and KPIT before moving into Python, machine learning and AI, and he also builds web apps with TypeScript and React. He writes the tutorials here himself, and every example is run before publishing so you see the real output. More about Bijay · Microsoft MVP profile · LinkedIn