React Diff Principle In-depth Analysis

React Diff Principle In-depth Analysis

Before understanding Diff, let's take a look at the structure of React's virtual DOM

This is the html structure

<div id="father">
  <p class="child">I am child p</p>
  <div class="child">I am child div</div>
</div>

This is the js code when React renders HTML. You can try it on babel

React.createElement("div", {id: "father"}, 
    React.createElement("p", {class: "child"}, "I am child p"),             
    React.createElement("div", {class: "child"}, "I am child div")
);

This shows that this is a tree structure.

React creates a tree (referred to as pre) when calling the render method, and returns a different tree (referred to as cur) the next time the render method is called. React will compare the differences between the pre and cur trees to determine how to update the UI efficiently and ensure that the current UI is synchronized with the latest tree cur.

In order to update the UI efficiently, React proposes an O(n) heuristic algorithm based on the following two assumptions:

1. Two different types of elements will produce different trees;

2. Developers can set the key attribute to tell the renderer which sub-elements can be kept unchanged under different renderings;

Diffing Algorithm

Layer-by-layer comparison

When comparing two trees, React compares them layer by layer and only compares DOM nodes within the same color box.

First, compare the root nodes of the two trees. Different types of root nodes will have different shapes. When the root node is an element of a different type, React will tear down the original tree and build a new one. For example, when an element changes from <a> to <img>, from <Article> to <Comment>, or from <Button> to <div>, a complete rebuild process is triggered.

//before
<div>
    <App/>
</div>
//after
<p>
    <App/>
</p>

React will destroy the App component (all its subcomponents are also destroyed) and recreate a new App component (including its subcomponents).

The following DOM structure conversion:

React will only simply consider the position changes of nodes in the same layer. For nodes in different layers, there are only simple creation and deletion. When the root node finds that A is missing from its child node, it will destroy A directly; and when D finds that it has an extra child node A, it will create a new A as its child node. Therefore, the actual operation for this structural transformation is:

A.destroy();
A = new A();
A.append(new B());
A.append(new C());
D.append(A);

Although this algorithm seems a bit "crude", it is based on the first assumption: two different types of elements will produce different trees. According to the React official documentation, this assumption has not caused serious performance issues so far. This of course also gives us a hint that maintaining a stable DOM structure will help improve performance when implementing our own components. For example, we can sometimes hide or show certain nodes through CSS instead of actually removing or adding DOM nodes.

Compare components of the same type

When a component is updated, the component instance remains unchanged, but changes in the data in state or props will call render to change the child elements in the component for update.

Comparing elements of the same type

When comparing two React elements of the same type, React will preserve the DOM nodes and only compare and update the properties that have changed.

<div className="before" title="stuff" />

<div className="after" title="stuff" />

React changes the className of div from before to after (similar to the merge operation of updating state in React).

Recursively on child nodes

By default (level-by-level comparison), when recursing over the children of a DOM node, React will traverse both lists of children at the same time; when a difference is found, a mutation is generated.

Therefore, when adding elements to the end of the list, the update overhead is relatively small. For example:

<ul>
  <li>first</li>
  <li>second</li>
</ul>

<ul>
  <li>first</li>
  <li>second</li>
  <li>third</li>
</ul>

React will first match the two <li>first</li> trees, then match the tree for the second element <li>second</li> , and finally insert the third element's <li>third</li> tree.

If you simply insert the new elements into the table header, the update overhead will be relatively large. for example:

<ul>
  <li>Duke</li>
  <li>Villanova</li>
</ul>

<ul>
  <li>Connecticut</li>
  <li>Duke</li>
  <li>Villanova</li>
</ul>

React won't realize that it should keep <li>Duke</li> and <li>Villanova</li> and will rebuild each child. This situation can cause performance problems.

Keys

To solve the above problems, React introduced the key attribute. When a child has a key, React uses the key to match the child in the old tree with the child in the newest tree. The following example improves the efficiency of tree conversion after adding a key:

<ul>
  <li key="2015">Duke</li>
  <li key="2016">Villanova</li>
</ul>

<ul>
  <li key="2014">Connecticut</li>
  <li key="2015">Duke</li>
  <li key="2016">Villanova</li>
</ul>

Now React knows that only the element with the '2014' key is new, and the elements with the '2015' and '2016' keys have simply moved. Therefore, only the element with key=2014 is created, and the remaining two elements are not created.

Therefore, it is best not to use the array subscript as the key value, because the order of the array may change. It is best to use the unique identifier (id or other attributes) carried by the data itself.

1. The role of key in virtual DOM:
1). Simply put: key is the identifier of the virtual DOM object, and key plays an extremely important role when updating the display.

2). In detail: When the data in the state changes, React will generate a new virtual DOM based on the new data, and then React will perform a diff comparison between the new virtual DOM and the old virtual DOM. The comparison rules are as follows:

a. The same key as the new virtual DOM is found in the old virtual DOM:
(1) If the content in the virtual DOM has not changed, directly use the previous real DOM
(2) If the content in the virtual DOM changes, a new real DOM is generated and then replaces the previous real DOM in the page.

b. The same key as the new virtual DOM is not found in the old virtual DOM
Create a new real DOM based on the data and then render it to the page

2. Problems that may arise when using index as key:
1. If you perform operations that destroy the order of data, such as adding or deleting data in reverse order:
Unnecessary real DOM updates will be generated ==> The interface effect is fine, but the efficiency is low.

2. If the structure also contains DOM of input class:
Will produce wrong DOM update ==> There is something wrong with the interface.
3. Attention! If there is no order-destroying operation such as adding or deleting data in reverse order,
It is only used to render the list for display, so there is no problem using index as the key.

The above is the detailed content of the in-depth analysis of the React Diff principle. For more information about the React Diff principle, please pay attention to other related articles on 123WORDPRESS.COM!

You may also be interested in:
  • Detailed explanation of virtual DOM and diff algorithm in react
  • React diff algorithm source code analysis
  • Detailed explanation of DOM DIFF algorithm in react application
  • A brief discussion on analyzing the Diff algorithm from the React rendering process
  • Example implementation of React diff algorithm

<<:  Solution to Ubuntu 18.04 not being able to connect to the network in VMware virtual machine

>>:  Introduction to MySQL statement comments

Recommend

When to use table and when to use CSS (experience sharing)

The main text page of TW used to have a width of 8...

How to uninstall MySQL cleanly (tested and effective)

How to uninstall Mysql perfectly? Follow the step...

Detailed explanation of the role of brackets in AngularJS

1. The role of brackets 1.1 Square brackets [ ] W...

Example of implementing the Graphql interface in Vue

Note: This article is about the basic knowledge p...

CSS inheritance method

Given a div with the following background image: ...

VMware Workstation is not compatible with Device/Credential Guard

When installing a virtual machine, a prompt appea...

Essential conditional query statements for MySQL database

Table of contents 1. Basic grammar 2. Filter by c...

Some problems you may encounter when installing MySQL

Question 1: When entering net start mysql during ...

WeChat applet realizes multi-line text scrolling effect

This article example shares the specific code for...

Using better-scroll component in Vue to realize horizontal scrolling function

About Recently, in the process of learning Vue, I...

Native Js implementation of calendar widget

This article example shares the specific code of ...

Summary of some tips on MySQL index knowledge

Table of contents 1. Basic knowledge of indexing ...

Implementation of docker view container log command

Why should we read the log? For example, if the c...

Four ways to switch tab pages in VUE

Table of contents 1. Static implementation method...