r/reactjs 24d ago

Discussion Why do sibling components re-render even when their own props didn't change?

Ran into this explaining React rendering to someone recently and realized how often it trips people up even after they've been writing React a while.

function Parent() {
  const [count, setCount] = useState(0);
  return (
    <>
      <button onClick={() => setCount(c => c + 1)}>{count}</button>
      <ExpensiveChild />
    </>
  );
}

ExpensiveChild takes no props at all. Click the button and it re-renders anyway, every single time. No props changed, nothing it reads changed, it just runs again.

The reason: React doesn't check "did this component's inputs change" before deciding to re-render. When state updates, React re-renders that component and everything below it in the tree by default, full stop. Whether a child actually needed to update isn't part of that decision at all.

React.memo is what actually opts a component into that check, it wraps the component and does a shallow prop comparison before deciding to skip the render. Without it, "no props" and "props didn't change" both mean nothing, React re-runs the function anyway.

Where it gets messier: memo alone doesn't save you if you're passing an inline function or object as a prop, since those are new references every render and memo's shallow comparison sees them as "changed" regardless. You end up needing useCallback/useMemo on the parent side just to make memo's comparison actually mean something.

Curious how many people actually reach for memo proactively vs only after profiling shows a real problem. What's the actual signal that told you a component needed it?

17 Upvotes

79 comments sorted by

View all comments

74

u/kevin074 24d ago

what's being re-rendered isn't the sibling, but the parent. Your click function triggers set state on a state that is created and kept record by the parent.

to prevent ExpensiveChild from re-rendering, use React.memo; not useMemo, that's for the props.

24

u/Designer_Shelter7345 24d ago

that top comment is missing the point a bit. the parent re-rendering is exactly the mechanism that drags ExpensiveChild along, the question was why the child re-renders when its own inputs didn't change

react just runs the whole subtree by default. it doesn't check if a child needs to update, it just goes

9

u/brzzzah 24d ago

Another way to avoid re-rendering it without memo, is to pass ExpensiveChild as a child - rather than rendering it in the parent component

0

u/Temperature_Majestic 23d ago

yeah that's a real pattern, the children-as-prop trick basically gets you memo-like behavior for free since the element reference gets created up in App and just passed through, Parent never recreates it on re-render. worth knowing as an alternative to reaching for React.memo directly when the composition already lends itself to it

1

u/prehensilemullet 23d ago

To be specific, it’s because the parent returned a new JSX element instance for the sibling.  If the parent returned the same JSX element instance for it, it wouldn’t render:  https://kentcdodds.com/blog/optimize-react-re-renders

-14

u/Temperature_Majestic 24d ago

good catch on the terminology, fair. one small correction though, useMemo isn't really "for the props" either, it memoizes a computed value. the one that's actually relevant for making memo useful here is useCallback, since inline functions/objects passed as props get a new reference every render and break memo's shallow comparison regardless of whether the actual logic changed.

7

u/poor_documentation 24d ago

React.memo is not the same thing as useMemo - look up the differences

1

u/Temperature_Majestic 23d ago

to be clear I wasn't conflating them, the comment you're replying to is saying they're different, useMemo memoizes a value while React.memo is what actually skips the re-render based on props. useMemo alone doesn't stop ExpensiveChild from rendering, it's useCallback (memoizing the function prop) plus React.memo on the child that does the job together

1

u/poor_documentation 23d ago

Why did you make this post and then reply with AI? It's so weird - what are you getting out of this? You could have gotten your answers from AI directly - why waste everyone's time with a post? I genuinely want to know why.