In React, when a parent component re-renders, isn't it true that the children with unchanged props should not need to re-render?
Asked Answered
U

1

8

I think the fact is that, when a parent component re-renders in React, in general, all the children components re-render as well.

I did one experiment to confirm:

https://codesandbox.io/s/currying-pine-r16rzi

  return (
    <div>
      <div>Time now is {timeNow.toLocaleTimeString()}</div>
      <TheTimeNow /><TheTimeNow />
    </div>
  );

This parent component re-renders, and <TheTimeNow /> has no change in props value (it has none), but it re-renders anyway and shows the updated time.

I think it is not the same to say, that React actually change the DOM, as I think the mechanism is that React use the previous virtual DOM to compare with the new virtual DOM, and update only the minimal actual DOM node as on document.documentElement as needed.

This can be seen if you use Google Chrome and do Inspect Element on the time statement: only the time portion changes and the other English words stay the same. Compare to this where all the nodes changes if it is plain JavaScript: https://jsfiddle.net/8sj2ugae/1/ when you do Inspect Element.

However, can't we argue that, if a child is <Foo /> and since there is no props passed to it, then <Foo /> really should not have changed, and it is wasteful to call Foo()? (if Foo is a functional component, or call the render() method if it is a class component.)

Now since all children re-renders, that means all their children also get re-rendered. Repeat this rule recursively, that would mean the whole subtree gets re-rendered.

My question is: is it true that they should not need to re-render if their props didn't change, or are there other factors that make them needing a re-render really?

Unlicensed answered 7/8, 2022 at 10:51 Comment(3)
If parent rerenders children rerender, unless they are optimized using React.memo or shouldComponentUpdate is used.Mediatize
I think I saw "children rerender because to help beginners to avoid any subtle 'not updated' bug"... but then if programmers start using useMemo() every where, it is really tight coupling. The team has to keep on thinking, oh this component we can use useMemo() but the other component cannot and this component now has to because reason XYZ makes it so... it is also very easy to have bugs this way, if the tight coupling itself isn't a problemUnlicensed
also, <Foo /> really needs no updating, logically speaking, I think. But it is like React just use a simple rule (and also a dumbed down rule) here, to update everythingUnlicensed
C
6

The answer is yes, there is no need to rerender. But in order to know this we need to compare a new props with a previous props. And this operation is not free.

Also if we do a shallow comparison we are increasing the probability of bugs. Someone might be expecting rerender after a deep props update.

Should React.memo be the deault behaviour? Will it improve the performance in most cases? We don't know. There is no evidence for that. More on this in Mark Erikson's post.

Here is a great article by Dan Abramov: Before You memo(). I consider two points regarding your question:

  1. In the future compiler might decide when to memoize a component.

  2. Component rendering doesn't mean that all it's children will be rerendered.

Here is an example:

const ParentComponent = ({ children }) => {
  const [state, setState] = useState(0);
  return <div>{children}</div>
}

If we update the state children will not be rerendered. React just uses a previous value. Here is an article by Kent C. Dobbs about this optimization technique.

One last thing. React.memo and useMemo are different. The first one is for component memoization and the second one is a hook for expensive calculations. There are also shouldComponentUpdate for class components and PureComponent which compare not only props but also a state.

Hopefully the answer and links will shed some light on this topic.

Carrack answered 10/8, 2022 at 13:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.