What is Reconciliation?
Reconciliation is the process that React does behind the scenes to render components and display components on the screen. React changes the DOM elements on the browser between different re-renders, based on state updates or rendering a new component. But it might not be clear how a piece of code in React executes or how reconciliation is implemented, therefore I have tried to explain my understanding of the reconciliation process in React.
Steps in the reconciliation process
- Trigger a render - Whenever a component is initially rendered using
render()
function or state is updated. - Render component - Here diffing process occurs if there is a re-render, else a new DOM tree is constructed.
- Commit to DOM - Put the changes on the browser dom which is done by
react-dom
.
Virtual DOM and Diffing
Virtual DOM - The virtual DOM is a programming concept where an ideal, or “virtual”, representation of a UI is kept in memory.
Diffing - The diffing algorithm of React compares two trees and returns the part which needs to be changed.
Whenever the render()
function is called React creates a new DOM tree and compares it with the virtual DOM using the diffing algorithm. The necessary changes are then painted on the browser DOM by react-dom
.
Some Examples
The diffing algorithm always checks for the root element first, if it is different then it destroys the previous DOM nodes and builds a new tree.
DOM elements having different root
//original element
<div>
<Navbar />
</div>
//updated element
<header>
<Navbar />
</header>
This will destroy the old DOM tree and create a new one because the root elements - <div>
and <header>
are different. Therefore, this will also render a new <Navbar />
component.
DOM elements having the same root
//original element
<h1 className="heading">Understanding reconciliation</h1>
//updated element
<h1 className="title">Understanding reconciliation in React</h1>
In this case, the DOM element <h1>
will be updated by changing the className
and the innerText
. The DOM tree won't be destroyed.
Rendering lists
//original list
<ul>
<li>item1</li>
<li>item2</li>
</ul>
//updated list
<ul>
<li>item1</li>
<li>item2</li>
<li>item3</li>
</ul>
Here, we have an unordered list with two <li>
items inside it. Adding a new <li>
at the end, React will compare both the lists and append a new child at the end.
//original list
<ul>
<li>item1</li>
<li>item2</li>
</ul>
//updated list
<ul>
<li>item3</li>
<li>item1</li>
<li>item2</li>
</ul>
But if we add a new <li>
at the start of the list, react will give the worst performance and mutate all the <li>
elements instead of adding only <li>item3</li>
.
Keys for rendering children
To solve the above problem React supports key
attributes for children to identify the children separately.
//original list
<ul>
<li key="1">item1</li>
<li key="2">item2</li>
</ul>
//updated list
<ul>
<li key="3">item3</li>
<li key="1">item1</li>
<li key="2">item2</li>
</ul>
This will help React know that <li>
with key="3" is the new element and others are the same, which will help in increasing the performance.
While keys solve this problem, we might face another problem if we are not using the keys properly. For example :
<li key={item.id}>{item.name}</li>
Here, we are rendering the lists dynamically and if the key
value itself keeps changing and is unstable, such as keys produced by Math.random()
, this will cause unnecessary recreation of children. Therefore, keys should be stable and unique.
Wrapping Up
Here are brief points about the reconciliation process :
- React doesn't re-render the DOM fully every time because of reconciliation and makes apps faster.
- Knowing about reconciliation helps us write better code keeping in mind the render process and avoiding writing any code which destroys the old component and renders a new component. This is a bad practice and should be taken care of.
Thanks for reading!! Give some reactions if you liked it. If you want to connect with me or see my projects, here's my portfolio link.