Reconciliation in react
Wasiu Idowu

Wasiu Idowu

Nov 1, 2022

Reconciliation in react

React provides a declarative API so that you don’t have to worry about exactly what changes on every update. This makes writing applications a lot easier, but it might not be obvious how this is implemented within React. This article explains the choices we made in React’s “diffing” algorithm so that component updates are predictable while being fast enough for high-performance apps.

Motivation

When you use React, at a single point in time you can think of the render() function as creating a tree of React elements. On the next state or props update, that render() fuction will return a different tree of React elements. React then needs to figure out how to efficiently update the UI to match the most recent tree.

There are some generic solutions to this algorithmic problem of generating the minimum number of operations to transform one tree into another. However, the state of the art algorithms have a complexity in the order of O(n3) where n is the number of elements in the tree.

If we used this in React, displaying 1000 elements would require in the order of one billion comparisons. This is far too expensive. Instead, React implements a heuristic O(n) algorithm based on two assumptions:

  1. Two elements of different types will produce different trees.
  2. The developer can hint at which child elements may be stable across different renders with a key prop.

In practice, these assumptions are valid for almost all practical use cases.

The Diffing Algorithm

When diffing two trees, React first compares the two root elements. The behavior is different depending on the types of the root elements.

Elements of Different Types

Whenever the root elements have different types, React will tear down the old tree and build the new tree from scratch. Going from <a> to  <img>, or from <Article> to <Comment>, or from <Button> to <div>  - any of those will lead to a full rebuild.

When tearing down a tree, old DOM nodes are destroyed. Component instances receive componentWillUnmount() . When building up a new tree, new DOM nodes are inserted into the DOM. Component instances receive UNSAFE_componentWillMount() and then componentDidMount() . Any state associated with the old tree is lost.

Any components below the root will also get unmounted and have their state destroyed. For example, when diffing:

<div>
  <Counter />
</div>

<span>
  <Counter />
</span>

This will destroy the old Counter and remount a new one.

Wasiu Idowu

Wasiu Idowu

Wasiu breaks down complex topics into smaller, simpler bits

Leave a Reply

Related Posts

Categories