20 Jul 2021
A Visual Guide to React Rendering - It Always Re-renders
When does a React component re-render? Is it when its state or props change?
Take a look at the gif above ๐
The structure of the app is: App > A > B > C
.
Here's a slightly simplified code:
Components A, B, and C don't have any props or state. Yet, they still re-render when the App renders.
In normal rendering, React does not care whether "props changed" - it will render child components unconditionally just because the parent rendered!
โ Mark Erikson - A (Mostly) Complete Guide to React Rendering Behavior
To illustrate this point further, let's add state to every component and track the behavior.
When the state of C changes, only C renders. But when the state of B changes, both B and C render. B renders because its state updates, and C renders because its parent renders.
When the state of A changes, A renders because of the state update, B renders because A rendered, and C renders because B rendered.
Avoiding re-renders
There are several ways to avoid unnecessary re-renders in React. In this article, I'll only focus on React.memo
and save other methods for future posts. If you're interested in alternatives to memo
, check out Dan Abramov's Before you memo().
Also, please keep in mind that in this post, I only explore re-renders caused by direct state updates or parent renders. I don't pass any props.
If you wrap a component in memo
, it won't re-render when its parent renders.
Notice that C updates when its state changes, but not when the parent renders.
Lifting memo up
Let's lift memo
up and see what happens.
The state updates of components A, B, and C produce the same results as before. But notice the state update on the App. Wrapping a component with memo
prevents the entire subtree of this component from re-rendering in response to a parent render.
That's why you might hear advice like this:
That React Component Right Under Your Context Provider Should Probably Use React.memo
โ Sophie Alpert - February 16, 2020
What about adjacent components?
The same rules apply to adjacent components. The component with memo
doesn't re-render in response to a parent render, and therefore, prevents its entire subtree from re-rendering.
Should I memo everything?
If memo
has such a great effect on performance, does it make sense to wrap everything with it? Well, not really. But this is a topic for another day. If you're interested, read Fix the slow render before you fix the re-render by Kent C. Dodds.