React’s Diffing algorithm

When comparing two trees, React first compares the root nodes of the two trees. Different types of root node elements have different shapes.

Compare elements of different types

When the root node has a different type of element, React disassembles the existing tree and creates a new one. For example, when an element changes from to , from

to

, or from


When a tree is removed, the corresponding DOM node is also destroyed. The component instance will execute the componentWillUnmount() method. When a new tree is created, the corresponding DOM node is created and inserted into the DOM. Component instances will execute the componentWillMount() method, followed by the componentDidMount() method. All states associated with the previous tree are also destroyed.

Components below the root node are also uninstalled and their state is destroyed. For example, when the ratio is more variable than:

<div>
  <Counter />
</div>

<span>
  <Counter />
</span>
Copy the code

React destroys the Counter component and reloads a new one.

Compares elements of the same type

When you compare two React elements of the same type, React preserves the DOM node and only compares and updates the changed attributes. Such as:

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

<div className="after" title="stuff" />
Copy the code

By comparing the two elements, React knows that it only needs to change the className attribute on the DOM element.

When updating the style property, React updates only the properties that have changed. Such as:

<div style={{color: 'red', fontWeight: 'bold'}} / >

<div style={{color: 'green', fontWeight: 'bold'}} / >
Copy the code

By comparing the two elements, React knows that it only needs to change the color style on the DOM element, not the fontWeight.

After processing the current node, React continues to recurse on the child nodes.

Compares component elements of the same type

When a component is updated, the component instance remains the same, so that state remains consistent across different renderings. React to update the component instance props to consistent with the latest element, and invoke the instance componentWillReceiveProps () and componentWillUpdate () method.

Next, the render() method is called, and the diff algorithm recurses over the previous result as well as the new one.

Recurse on the child nodes

By default, React iterates through lists of both child elements while recursively iterating through the child elements of a DOM node. When a difference occurs, a mutation is generated.

When adding an element at the end of the child element list, the change overhead is lower. Such as:

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

<ul>
  <li>first</li>
  <li>second</li>
  <li>third</li>
</ul>
Copy the code

React matches two

  • first
  • trees, then matches the second< li>second tree, and finally inserts the

  • third
  • tree of the third element.

    If implemented simply, inserting at the head of the list can be a performance drag and can be expensive. Such as:

    <ul>
      <li>Duke</li>
      <li>Villanova</li>
    </ul>
    
    <ul>
      <li>Connecticut</li>
      <li>Duke</li>
      <li>Villanova</li>
    </ul>
    Copy the code

    React will mutate for each child element instead of keeping the same

  • Duke
  • and

  • Villanova
  • subtrees complete. Inefficiencies in this case can cause performance problems.

    Keys

    To address these issues, React supports the key attribute. When a child element has a key, React uses the key to match the child element of the original tree with the child element of the latest tree. The following example makes a previously inefficient conversion efficient 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>
    Copy the code

    React now knows that only elements with the ‘2014’ key are new; elements with the ‘2015’ and ‘2016’ keys are simply moved.

    In the real world, it is not difficult to generate a key. The element you want to present may already have a unique ID, so the key can be extracted directly from your data:

    <li key={item.id}>{item.name}</li>
    Copy the code

    When this is not the case, you can add an ID field to your model, or generate a key using a portion of the content as a hash. This key doesn’t need to be globally unique, but it needs to be unique in the list.

    Finally, you can also use the element’s index in the array as a key. This strategy works well when elements are not reordered, but diff slows down once the order changes.

    Component state may encounter some problems when subscription-based components are reordered. Because component instances decide whether to update and reuse based on their key, if the key is a subscript, the order in which changes are made changes the current key, causing states of uncontrolled components (such as input fields) to tamper with each other and change unpredictably.