How to understand the virtual DOM
Virtual DOM is basically a tree based on JavaScript objects (vNodes), which are described by object attributes. In fact, it is just a layer of abstraction from the real DOM. Eventually, the tree can be mapped to the real world through a series of operations.
In JavaScript, the virtual DOM is represented as an Object Object. It contains at least three attributes: tag, attrs, and children. Different frameworks may have different names for these three attributes.
However, in general, the nodes of the Virtual DOM object correspond to the attributes of each position in the DOM Tree one by one, because the Virtual DOM is created to better render the Virtual nodes on the view, that is, to turn the Virtual DOM into real DOM nodes, and improve the rendering performance of the view.
Advantages of the virtual DOM
To better understand the virtual DOM, you need to know what it does. Or what advantage it has over manipulating the real DOM directly.
- Reduce DOM manipulation
One advantage of the virtual DOM is that it reduces DOM manipulation.
There are 1000
-
, if you change 10 of them, if there is no virtual DOM, the simple and straightforward way to do this is to replace the whole
-
and re-render, which is actually a lot of unnecessary DOM manipulation.
If the virtual DOM is used, the nodes of the virtual DOM object correspond to the attributes of each position on the DOM Tree one by one. During the mapping to the view, the virtual DOM compares the virtual node with the old virtual node used in the last rendering view to find out the nodes that really need to be updated for DOM operation. This avoids manipulating other DOM that doesn’t need to be changed. The algorithm used to compare the two virtual DOM is DOM Diff.
And to be clear, DOM manipulation is not slow at the JS level. In most cases, the virtual DOM is faster than the DOM because fewer DOM nodes need to be updated than the native DOM, and the browser redraws in less time. Moreover, the advantage of virtual DOM does not lie in a single operation. With the comparison algorithm, it can combine multiple operations into one operation, and update views reasonably and efficiently with a large number of frequent data updates.
- cross-platform
Another advantage of the virtual DOM is that it can be cross-platform.
Because the virtual DOM is based on JavaScript objects, it is essentially a JavaScript object and does not depend on the real platform environment, making it cross-platform. It can be turned into a DOM in the browser and a corresponding render object on other platforms.
DOM diff
DOM diff is an algorithm for comparing the differences between two virtual DOM trees.
Diff algorithm only compares the virtual nodes at the same level of the two trees, recursively, and finally realizes the update of the whole DOM tree.
Diff algorithm mainly includes several steps:
- Use JS object to represent the structure of the DOM tree, and then build a real DOM tree according to this object, inserted into the document.
- When the state changes, a new object tree is rebuilt. Then compare the new tree with the old one, and note the differences between the two trees
- Finally, the recorded differences are applied to the real DOM tree built, and the view is updated
DOM Diff makes comparisons on three levels
- Tree Diff
- First, the hierarchy of the tree structure is compared, and all the child nodes under the same parent node are compared.
- Then see what type of node it is. If it is a Component, do Component Diff;
- If the node is a tag or Element, do Element Diff.
- Component Diff (Component comparison)
-
If the component type is the same, continue to compare the structure of its virtual DOM by hierarchy.
-
If the component type is different, replace all the content of the entire component
- Element Diff
- If the node is a native tag, the tag name is compared to determine whether to replace or update the attribute
- Then enter the tag descendant recursion Tree Diff
DOM Diff’s problem
When comparing elements, diff provides three node operations when the DOM is at the same level: delete, insert, and move
There is no key problem
Suppose there are two sets of old and new nodes:
Set of old nodes: {A,B,C,D}
New node set: {B,A,D,C}
This is a later comparison, and you see that B! = A, create and insert B into new set, delete old set A; Similarly, create and insert A, D, and C, and delete B, C, and D.
It’s tedious to do this, but you just have to move the nodes around. So developers can add unique keys to distinguish nodes.
After a Key is added to the element, React/Vue performs differentiation comparison during Diff. That is, the nodes in the old and new sets are all the same. Therefore, node deletion and creation are not required, but nodes in the old set are moved to the new set.
Not adding a key will cause the entire collection to be deleted and then added, without moving the DOM. In addition, not adding a key can cause data update bugs
Suppose v-for is used to generate three sets of data without keys
<div v-for="(item, index) in list">{{item.value}}<div/>
Copy the code
index | value |
---|---|
0 | Xiao Ming |
1 | The little red |
2 | The little flower |
Then delete the second set of data, xiaohong, after deleting it looks like this:
index | value |
---|---|
0 | Xiao Ming |
1 | The little red |
The little red that should be deleted is still there, but the little flower is gone.
React/Vue determines that the components before and after the React/Vue change are of the same type, and the content of the props does not change.
The process is as follows:
- 1 doesn’t change, so I’m going to reuse the 1 in place;
- 2 becomes 3, and the descendant element is reused in place (the descendant element’s data/state attribute is not affected by 2 becoming 3).
- If 3 is gone, then all descendants are deleted
The solution is to add a unique key to let Diff know that even components of the same type are named, and update the view without error
Note that index should also not be used as the key of the loop, as in the figure above, index changes from (0,1,2) to (0,1) instead of (0,2). This also causes update errors.
(after)