DEV Community

loading...
Cover image for Understanding Rendering in React β™» βš›οΈ

Understanding Rendering in React β™» βš›οΈ

teo_garcia profile image Mateo Garcia ・6 min read

Hey there! πŸ‘‹πŸΌ

I'm Mateo Garcia, I co-organize a community in Medellin, Colombia called React Medellin. This year I started a series of posts called 'Coding with Mateo'; My first post was about 6 ways to write a React component.

Coding with Mateo billboard

Today I want to share with you what I have researched for a couple of weeks about how rendering works in React. To begin with, I will say that the concept of rendering in React is a little different from how we know it. Let's find out why.

Table of Contents

1.Introduction
2.VirtualDOM
3.Render
4.Reconciliation
5.Commit
6.An example

Introduction

You are probably here because you have worked with React, interacted with their APIs, changed the state of your components, and seen the magic happen. However, it is sometimes useful to go into a little more detail about how React does what it does. Performance problems can appear when your React application is continuously re-rendering, the application has scaled considerably and, the components are complex and expensive to represent. That's why Understanding rendering in React is something that all of us who use this library should understand.

To understand why React is so fast it is important to know these four concepts:

  1. Virtual DOM.
  2. Render.
  3. Reconciliation.
  4. Commit.

Let's get started

VirtualDOM

The Virtual DOM was a strategy that appeared to solve the modifications or mutations that the DOM suffers when using a web or mobile application. Rendering the entire document tree is too costly as applications become more complex; by mutations, we can understand any change that the DOM can undergo: an insertion/modification/deletion of an element or its properties.

Thus, the Virtual DOM came to represent the DOM tree in memory. Perform calculations using the state and props and finally decide which elements of the actual DOM (the browser one, I mean haha) should be mutated. From the official React website:

The virtual DOM (VDOM) is a programming concept where an ideal, or β€œvirtual”, representation of a UI is kept in memory and synced with the β€œreal” DOM by a library such as ReactDOM. This process is called reconciliation.

Initially, I said that the concept we normally know as rendering is different in React, I personally considered rendering as the procedure of synchronizing changes in the DOM. React synchronizes the changes in the DOM through three steps.

Virtual DOM in a graphic

Render

Rendering is a process that is triggered by a change of state in some component of your application, when a state change occurs React:

React render phase illustration

  • It will collect from the root of your App all the components that requested a re-render because their state or their props changed.
  • It will invoke these components
    1. If you use function components it will invoke the function itself, something like Header(props).
    2. If you use class components it will invoke YourComponent.render().

Even when the process's name is rendering, at this point, the DOM has not been modified or altered, which could be a little tricky if you think as I did, about the meaning of render.

Since we normally use JSX, the code will be transformed to React.createElement(...). The output of the createElement will describe how the application should look like in the next version of the render through the next stage called:

Reconciliation

Once the re-rendering has happened, React has the context of two versions of the React.createElement output, the version executed before the state change occurred, and the version executed after the state has changed.

Reconcilier process illustration

At this point two objects are describing the UI, React through a heuristic algorithm of order O(n^3) will be able to determine which elements need to be represented again.

Among technical details the React team tells us some aspects about how React identifies which elements were affected:

  1. Elements that changed type must be recreated.

  2. Changes within the attributes of an element are replaced, without unmounting the element.

  3. Upgrades within the element's children recreate all children

  4. Updates within child elements that use key as attributes are compared and only new items are represented.

Commit

After React calculated all the changes that should be made in the application tree, react-dom appears for the browser and react-native for the mobile platforms, which make the modifications to the browser or mobile app API (finally! πŸ₯³). Synchronously React will clean up the past layout effects, run the new layout effects, then the browser will paint the DOM, after that, React will clean up the past effects and mount the new ones; when I talk about effects I refer to the lifecycles method such as useLayoutEffect and useEffect.

Commit phase illustration

To explain the lifecycles method part a little bit more, I bring to you this wonderful graph that Donavon West and his contributors created. This is the project repo, check it out!

React Hooks lifecycle methods flow

Before moving on to the example, it is important to understand that under normal conditions, if a component calls render, it will automatically do so for all its children. However it is possible to prevent certain components from being re-rendered under certain special cases, I have in my plans to talk about it, however, you can read about React.PureComponent, React.memo, React.useMemo, and React.useCallback.

Example

Consider the following example.
Rendering example

Here's the code

import * as React from "react";
import { useRenderTimes } from '../../utils';

function getRandomHEX() {
  return `#${Math.floor(Math.random() * 16777215).toString(16)}`;
}

function Header() {
  const [color, setColor] = React.useState("#111");
  const count = useRenderTimes();
  return (
    <header style={{ backgroundColor: color }}>
      <p>Header component has re-rendered {count} times</p>
      <button onClick={() => setColor(getRandomHEX())}>Click</button>
    </header>
  );
}

function Footer() {
  const count = useRenderTimes();
  return (
    <footer>
      <p>Footer component has re-rendered {count} times</p>
    </footer>
  );
}

function App() {
  const count = useRenderTimes();
  return (
    <>
      <Header />
      <main>
        <p>Hey, nice to see you again πŸ‘‹πŸΌ</p>
        <p>The App component has re-rendered {count} times</p>
      </main>
      <Footer />
    </>
  );
}

export { App };
}
Enter fullscreen mode Exit fullscreen mode

useRenderTimes is a hook that will allow us to accumulate the number of times a component is re-rendered. I saw it in a post by Kent C Dodds, so thanks!

import * as React from 'react';

function useRenderTimes() {
  const renderRef = React.useRef(0);

  React.useEffect(() => {
    renderRef.current = renderRef.current + 1;
  });

  return renderRef.current;
}

export { useRenderTimes };
Enter fullscreen mode Exit fullscreen mode

The <Header /> component has its own state, which will be changing once we start pressing the button. Let's take a look

Rendering example in the second render

What just happened here is:

  1. An event in the <Header /> component triggered a state change. A render was scheduled.
  2. VirtualDOM started analyzing which components were marked as needing to be re-rendered. Only <Header /> needed it.
  3. Through the reconciliation step, it was identified that the style of the <header></header> was changing.
  4. Dispatched a commit to DOM.
  5. Boom, we see the change of the background color.

Final thoughts

Although rendering in React is a process that can become complex, we must recognize the excellent work done by the entire React Team to improve the day to day experience in web development. Knowing the deeper parts of a tool can be useful for people who are just starting to discover it, as well as for people who have been using it for a long time and want to understand what was going on behind the scenes.

I want to thank the experts who continually strive to share all the knowledge in the most understandable way possible, some of them are Mark Erikson and Kent C Dodds. I leave you the link to their blogs. Each article is a gold mine and needs to be recognized.

If you found this post useful and would like to see more content, you could react to this post, which would make me very happy. If you have any comments or corrections that could improve this post, I would be glad to receive them. Thank you for your time πŸ‘‹πŸΌ πŸ’™.

Discussion (16)

pic
Editor guide
Collapse
adarsha profile image
Adarsh Kumar Bhautoo

Great article!

Collapse
teo_garcia profile image
Mateo Garcia Author

Thank you, Adarsh :)

Collapse
dthakur001 profile image
dthakur001

NICELY EXPLAINED!!!

Collapse
teo_garcia profile image
Mateo Garcia Author

Thank youu :)

Collapse
gilesomofa profile image
Giles Smith

Great article. Nice succinct explanations!!!! Great for a newbie.

Collapse
yarivshamash profile image
Yariv Shamash

Super nice! and makes sense of it all.
Thanks :)

Collapse
teo_garcia profile image
Mateo Garcia Author

Thank you, Yariv!

Collapse
maxkoretskyi profile image
Max Koretskyi • Edited

If anyone's interested, here's a more in-depth coverage of the process described in the article indepth.dev/posts/1008/inside-fibe...

Collapse
melnikkk profile image
Alexander Melnik

Good job! Thank you for this article!)

Collapse
teo_garcia profile image
Mateo Garcia Author

Thank you, Alexander :)

Collapse
killianfrappartdev profile image
Killian Frappart

Perfectly explained and interesting topic! Well done πŸ‘

Collapse
teo_garcia profile image
Mateo Garcia Author

Thank you for reading it, Killian :)

Collapse
ohpyupi profile image
supergentle

I think the heuristic algorithm's time complexity drops to O(n) with some constraints. reactjs.org/docs/reconciliation.ht...

Collapse
teo_garcia profile image
Mateo Garcia Author

You're right πŸ€”

Collapse
naveadkazi profile image
Navead Kazi

Easy to understand and knowledgeable article

Collapse
teo_garcia profile image