This warning appears when rendering is no longer pure. A component should calculate JSX during render, not trigger updates to itself, its parent, or another component while that calculation is happening.
The fix is usually to move the update into an event handler for user actions or into useEffect for updates that must happen after React commits the render.
This React warning occurs when a component triggers a state update in another component during the render phase. React's rendering must be a pure, side-effect-free process. Calling setState or a state updater function during rendering "" even indirectly through a child component "" violates this rule and can cause infinite render loops or inconsistent UI states.
// ❌ Problem "" setState called during render
function Child({ onUpdate }) {
onUpdate("new value"); // Called during render!
return <div>Child</div>;
}
// ✅ Solution "" move to useEffect
function Child({ onUpdate }) {
useEffect(() => {
onUpdate("new value"); // Called after render
}, [onUpdate]);
return <div>Child</div>;
}
Calling a state setter directly in the component body (outside of event handlers or effects) triggers a state update during the render phase, causing React to warn and potentially loop.
When a child component calls a parent's state setter (passed as a prop) directly in its render body, it updates the parent's state while the parent is still rendering, causing this warning.
A useEffect without a dependency array runs after every render. If it updates state, it triggers another render, which runs the effect again "" creating an infinite loop that also triggers this warning.
Passing onClick={setState(value)} instead of onClick={() => setState(value)} immediately calls the function during render instead of waiting for the click event.
function App() {
const [count, setCount] = useState(0);
// ❌ Called during render "" causes warning
setCount(count + 1);
return <div>{count}</div>;
}
function App() {
const [count, setCount] = useState(0);
// ✅ State updates in event handlers
const handleClick = () => setCount(c => c + 1);
return <button onClick={handleClick}>{count}</button>;
}
function Parent() {
const [title, setTitle] = useState("");
return <Child setTitle={setTitle} />;
}
function Child({ setTitle }) {
setTitle("Hello from Child"); // ❌ Called during render!
return <div>Child</div>;
}
function Child({ setTitle }) {
// ✅ Use useEffect to update parent after render
useEffect(() => {
setTitle("Hello from Child");
}, []); // Empty deps "" runs once after mount
return <div>Child</div>;
}
function App() {
const [data, setData] = useState(null);
useEffect(() => {
fetchData().then(result => setData(result));
// ❌ No dependency array "" runs after every render!
});
return <div>{data}</div>;
}
function App() {
const [data, setData] = useState(null);
useEffect(() => {
fetchData().then(result => setData(result));
}, []); // ✅ Empty array "" runs only once after mount
return <div>{data}</div>;
}
function App() {
const [active, setActive] = useState(false);
return (
// ❌ setActive(true) is called immediately during render!
<button onClick={setActive(true)}>Activate</button>
);
}
function App() {
const [active, setActive] = useState(false);
return (
// ✅ Arrow function wraps the call "" only runs on click
<button onClick={() => setActive(true)}>Activate</button>
);
}
React may call render more than once, especially in development Strict Mode. If rendering also changes state, the same render calculation can trigger another render, which can trigger another update, making the UI unpredictable.
A pure render reads props and state and returns JSX. Side effects such as setState, navigation, subscriptions, storage writes, and analytics should happen after render or in response to events.
This warning often appears when a child component checks a prop and immediately calls a parent setter during render. The child render is still in progress, but the parent update asks React to start another render path.
Move that parent update into useEffect with a precise dependency array. If the update is caused by a user action, move it into the event handler instead.
function Child({ count, setStatus }) {
if (count > 10) {
setStatus("limit reached"); // Wrong during render
}
return <p>{count}</p>;
}
function Child({ count, setStatus }) {
useEffect(() => {
if (count > 10) {
setStatus("limit reached");
}
}, [count, setStatus]);
return <p>{count}</p>;
}
Calling a setter while building JSX.
Calculate JSX only during render.
Fixing the warning with setTimeout.
Use useEffect or event handlers based on the cause.
Storing every derived value in state.
Compute derived values from props and state when possible.
React's rendering must be a pure, deterministic process. Updating state during render creates side effects that can cause inconsistent UI, infinite loops, and unpredictable behavior.
In React 16-17 it was a warning. In React 18 it may throw an error in some cases. Either way, it indicates a bug that should be fixed "" the component will likely behave incorrectly.
Pass a callback function from parent to child as a prop. The child should call this callback inside a useEffect (for mount-time updates) or inside an event handler (for user-triggered updates).
"Cannot update while rendering" is about calling setState during the render phase. "Too many re-renders" is about setState being called so frequently that React hits its render limit (usually 50 renders).
useEffect itself runs after render, so it does not directly cause this warning. However, if useEffect has no dependency array and updates state, it can trigger infinite re-renders which may surface related warnings.
Explore 500+ free tutorials across 20+ languages and frameworks.