Behind the scenes of how react works.

February 11, 2023

Let's start with the basics by understanding what a component is and how it works. A component is like a blueprint or template of a UI that returns a React element in the element tree, it is usually written in JSX. From blueprint, we can create one or multiple component instances when we use the component. Each component instance has its own state, props, and lifecycle methods mount, update/re-render, and unmount.

component-blueprint image

When using a component technically its a component instance each component instance will return a react element.Component is usually written in JSX however JSX in transplied to vanilla js with the React.createElement function calls by the transpilers like babel or other transpilers. So using component will return a react element that element is a imutable javscript object with necessary properties that react keeps in memory to create DOM elements for the current component instance.

The term Virtual Dom is not used by react official docs anymore rather they say react tree. But i will use the term Virtual DOM because there will be so many tree in react and it might confuse some of you. 😁

component to dom elements image

💡 The $$typeof property in react element is used by react to prevent from cross site scripting attacks. notice that the value of the property is Symbol which is a primitive data type in js which cannot be transmitted via JSON. That means these symbol cannot come from any API call.So if a hacker send the fake component from any api react will not see the typeof:Symbol property and not add that fake react element to the DOM.

Let's now discuss the subject I mentioned in the component flowchart figure. Basically we will learn steps of how react renders the ui. Just keep in mind that rendering term doesnot mean its updating the real DOM directly or produces any visual changes instead there are some important process invloved while rendering.

1. Render triggered

Rendering process is started by react when a render is triggered mostly on the initial render and state update in any component instances also called re-render. Render triggred is for entire applications but does not update the dom for all.

2. Render Phase

In this process react calls the component functions and figures out how DOM should be updated to reflect the state changes however it doesnot update the real dom in this phase, it happens internally it does not produces any visual changes. In the beginning react goes through the entire component tree take all the component instances that causes render and this will create updated react elements and all together it will create a js object also called Virtual DOM. Virtual Dom is a tree of all react element created from all the instances from the component tree.

Virtual Dom is cheap and fast to create multiple trees even if the component tree is very huge.

Ui tree to virtual dom image

Updating a state in a parent component causes all of its children to be re-render even if children's state or props are not change. So again when a state changes in somewhere in application it will create a new virtual dom which is cheap and fast however writing to the DOM is not cheap and fast. For example in a large complex app a state changed somewhere it would be extremly unoptimized and wastefull to write to the DOM from scratch, only a small portion of the DOM should be updated the rest should be resued except for inital render. And thats what react exactly what react will do with the process called Reconcilation.

Reconcilation is a process of deciding which DOM elements needs to be inserted, updated, and deleted with a latest state changes with help of fiber(React v16+) and the diffing algorithm. Now lets cover the process after Virtual DOM is created, On the inital render of the application, based on that virtual dom, fiber creates another tree which is called Fiber tree.It is special internal tree where for each component instance and Dom element there is one fiber. unlike virtual dom fiber tree is not re created on every render, it is never destroyed because it is mutable data structure which gets mutated on every render. i said each component instance hold its own state props at beginning but internally fiber is the one that takes care of it since there is each fiber for each component instance has its props, state, side effects, hooks and work queue.

virtual dom to fiber tree

3. Commit Phase

In this phase react writes the DOM to insert ,update or delete some elements in order to keep sync the state with the application by sending the list of dom updates to do in the current fiber tree.

Before the commit phase react library was handling the rendering process but commit phase is handle by react dom. React itself does not touch the DOM nor Native Platfrom (iOS and andriod). React does even know where the result of render phase will be committed and painted, only render phase is handled by react because it was designed to be used independently for multiple platform. Meaning react can be used to develop web applications using react dom, similarly react native to develop iOS and andriod applications with the Native components like View, Image, Pressable, etc . and even videos using Remotion.

4. Browser Paint

In this phase the browser will notice that the DOM has been updated so it repaints the screen, this phase has nothing to do with react but this final step that users see the changes in the browser.If you want to know more about how this is handled by browsers, you can click here.

virtual dom to fiber tree

Diffing

I mentioned about diffing algorithm in the reconcilation process but did not talked much about it. Of course diffing algorithm is very complex so i will just discuss the basics like what is diffing algorithm and how it works. Diffing algorithm is part of reconcilation process. Diffing is comparing between elements step by step between two renders based on their position in the react tree. Diffing algorithm uses two basic assumptions:

1. Two element of different element type will produce different tree

When changing the div to header the element type is changed so it will distroy the tree from the parent component, rebuild with the new parent header from div in this example and also its state will be reset.

<>
  <div>
    <SearchBar />
  </div>
  <main>lorem</main>
</>
 
 
<>
  <header>
   <SearchBar />
  </header>
  <main>lorem</main>
</>

There are many senarios where same position and same element will be present in the element tree those elements will not be destroyed nor their state. meaning the component's state will be preserved.

<>
  <header className="hidden">
   <SearchBar />
  </header>
  <UserProfile/>
</>
 
<>
  <header className="active">
   <SearchBar />
  </header>
  <UserProfile/>
</>

You may see as the element has changed from the above example but actually only the className attribute has been changed not the element type. And this behaviour is absolutely needed because when the prop and attribute changed it does not makes sense to change the whole element, react will simply mutate the react tree remember which is simply a mutable javscript object.

2. Element with stable key prop stays the same in every render

From the above explanation you guys should be clear about two things in diffing algorithm:

Same element in the same position means state is preserved so that is the standard way of updating the tree by react. However we donot want this behaviour in our application for examples mapping a list and displaying a component, tabbed component, accordion etc.

Let's see clearly with a code example:

{
  activeTab <= 1 ? (
    <TabContent item={content.at(activeTab)} />
  ) : (
    <DifferentElementType />
  );
}
Without key prop image

In the above example there are TabContent component which are of same element type. The TabContent has its own title, body and likes state . But did you notice in the picture that the likes of one TabContent is same on another TabContent. So its clearly an issue where we want to reset the state in another TabContent. These types of situation will come when we map a list item and in accordion or other similar components.

So to solve that issue the key prop comes.

{
  activeTab <= 1 ? (
    // added key prop
    <TabContent item={content.at(activeTab)} key={content.at(activeTab).id} />
  ) : (
    <DifferentElementType />
  );
}
Wit key prop image

Notice after adding key prop the state of TabContent is reset when we render same element in same tree position. that is because after adding unique key to the element react treats the element as a different element so the tree is changed and so the state also. So thats why we add the key prop while mapping a list or in a tab or accordion component when we want to reset the state. However the value should be really unique not like index that we get as an second argument in map function but a unique id like one from uuid package.

References

If you liked it share it with your friends or colleague