Why React Re-Renders?

So, I'll be honest. I had been working professionally with React for years without really understanding how React's re-rendering process worked. 😅

I think this is true for lots of React developers. We understand enough to get by, but if you ask a group of React developers a question like “What triggers a re-render in React?”, you'll likely get a handful of different hand-wavy answers.

There are a lot of misconceptions out there about this topic, and it can lead to a lot of uncertainty. If we don't understand React's render cycle, how can we understand how to use React.memo, or when we should wrap our functions in useCallback??

In this tutorial, we're going to build a mental model for when and why React re-renders. We'll also learn how to tell why a specific component re-rendered, using the React devtools.

Link to this headingThe core React loop

So, let's start with a fundamental truth: Every re-render in React starts with a state change. It's the only “trigger” in React for a component to re-render.

Now, that probably doesn't sound right... after all, don't components re-render when their props change? What about context??

Here's the thing: when a component re-renders, it also re-renders all of its descendants.

Let's look at an example:

javascript
javascript

javascript
javascript

javascript
javascript
javascript
javascript
javascript

In this example, we have 3 components: App at the top, which renders Counter, which renders BigCountNumber.

In React, every state variable is attached to a particular component instance. In this example, we have a single piece of state, count, which is associated with the Counter component.

Whenever this state changes, Counter re-renders. And because BigCountNumber is being rendered by Counter, it too will re-render.

Here's an interactive graph that shows this mechanic in action. Click the “Increment” button to trigger a state change:

Alright, let's clear away Big Misconception #1: The entire app re-renders whenever a state variable changes.

I know some developers believe that every state change in React forces an application-wide render, but this isn't true. Re-renders only affect the component that owns the state + its descendants (if any). The App component, in this example, doesn't have to re-render when the count state variable changes.

Rather than memorize this as a rule, though, let's take a step back and see if we can figure out why it works this way.

React's “main job” is to keep the application UI in sync with the React state. The point of a re-render is to figure out what needs to change.

Let's consider the “Counter” example above. When the application first mounts, React renders all of our components and comes up with the following sketch for what the DOM should look like:

HTML

<main>
  <p>
    <span class="prefix">Count:</span>
    0
  </p>
  <button>
    Increment
  </button>
</main>
<footer>
  <p>Copyright 2022 Big Count Inc.</p>
</footer>

When the user clicks on the button, the count state variable flips from 0 to 1. How does this affect the UI? Well, that's what we hope to learn from doing another render!

React re-runs the code for the Counter and BigCountNumber components, and we generate a new sketch of the DOM we want:

HTML

<main>
  <p>
    <span class="prefix">Count:</span>
    0
  </p>
  <button>
    Increment
  </button>
</main>
<footer>
  <p>Copyright 2022 Big Count Inc.</p>
</footer>

Each render is a snapshot, like a photo taken by a camera, that shows what the UI should look like, based on the current application state.

React plays a “find the differences” game to figure out what's changed between these two snapshots. In this case, it sees that our paragraph has a text node that changed from 0 to 1, and so it edits the text node to match the snapshot. Satisfied that its work is done, React settles back and waits for the next state change.

© 2023 - Santosh Gudikandula. All Rights Reserved.