React: Cannot Update a Component While Rendering a Different Component

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
A React app showing the console warning that a component cannot be updated while a different component is rendering
React names both components: the one being updated, and the one that was rendering.

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>
  );
}
A React counter showing two after two clicks, with the onClick handler passed as an arrow function rather than called during render
Two clicks, count of two: the handler runs on the click, not during render.

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
A React app with city buttons showing the filtered order count and total calculated during render
Clicking Denver re-renders with a new list and total, with no extra state.

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 wroteWhat happensFix
onClick={setOpen(true)}Runs during renderonClick={() => setOpen(true)}
Child calls props.setX(...) in its bodyWarning, then a loopCall it in a handler or an effect
setTotal(...) to mirror a propExtra render, easy to desyncCalculate the value during render
Parent setter inside a child’s renderWarning naming both componentsLift the logic or use a callback
Own setter during own render, guardedAllowed, one extra renderNothing to fix

More React troubleshooting guides:

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.

Leave a Comment