What is Reconciliation in React?
Reconciliation is the core process behind React’s fast rendering, enabling it to update the user interface efficiently. This article explains what reconciliation is, how the Virtual DOM works, and the diffing algorithm React uses to update the real DOM with minimal performance overhead.
The Virtual DOM and Reconciliation
In traditional web development, directly manipulating the Real DOM (Document Object Model) is slow and resource-intensive. React solves this by keeping a lightweight representation of the UI in memory, known as the Virtual DOM.
When a component’s state or props change, React creates a new Virtual DOM tree. Reconciliation is the process of comparing this new Virtual DOM tree with the previous one to figure out the most efficient way to update the Real DOM. This comparison is done using a highly optimized “diffing” algorithm.
How the Diffing Algorithm Works
Comparing two trees of elements normally has a complexity of \(O(n^3)\), which is too slow for real-time UI updates. To make this fast, React applies a heuristic algorithm with \(O(n)\) complexity based on two main assumptions:
- Two elements of different types will produce different trees.
- The developer can hint at which child elements may be stable across
renders with a
keyprop.
React implements these assumptions through specific rules during the diffing process.
1. Elements of Different Types
If the root elements of two trees have different types (for example,
changing a <div> to a <span>, or a
<Counter> to a <Header>), React
will tear down the old tree and build the new tree from scratch. * Any
state associated with the old components is destroyed. * The lifecycle
methods for unmounting and mounting are triggered.
2. DOM Elements of the Same Type
When comparing two React DOM elements of the same type (for example,
two <div> elements), React looks at the attributes of
both. It keeps the underlying DOM node and only updates the attributes
or CSS styles that have changed.
<!-- Old Element -->
<div className="before" title="stuff" />
<!-- New Element -->
<div className="after" title="stuff" />In this example, React will only modify the className on
the DOM node, leaving the title attribute untouched.
3. Component Elements of the Same Type
When a component updates, the instance remains the same, meaning state is maintained across renders. React updates the props of the underlying component instance to match the new element and triggers a re-render.
Recursing on Children and the Role of Keys
By default, when recursing on the children of a DOM node, React iterates over both lists of children at the same time and generates a mutation whenever there’s a difference.
If you append an element at the end of a list, the transition is efficient:
<ul>
<li>First</li>
<li>Second</li>
</ul>
<!-- New Tree -->
<ul>
<li>First</li>
<li>Second</li>
<li>Third</li> <!-- React inserts this easily -->
</ul>However, if you insert an element at the beginning, React will mutate every child because it compares the old first child with the new first child, finds a mismatch, and rebuilds the rest of the list.
Solving List Inefficiencies with Keys
To solve this performance bottleneck, React supports the
key attribute. When children have keys, React uses them to
match children in the original tree with children in the subsequent
tree.
<ul>
<li key="a">First</li>
<li key="b">Second</li>
</ul>
<!-- New Tree -->
<ul>
<li key="c">Third</li>
<li key="a">First</li>
<li key="b">Second</li>
</ul>Because of the unique keys a, b, and
c, React knows that the elements with keys a
and b have simply moved, and it only needs to insert the
new element with key c at the top.
Summary
Reconciliation is the engine that allows React developers to write declarative UI code without worrying about manual DOM manipulation. By using the Virtual DOM and a smart diffing algorithm, React calculates the exact set of changes needed to update the screen, ensuring web applications remain highly performant.