Virtual DOM
#react
What is Virtual DOM?
DOM
Document Object Model
A standardized API for displaying HTML, XHTML, and XML documents in a tree structure.
It connects JavaScript to HTML.
DOM Nodes are directly accessible (e.g., getElementById).
Each node in the tree represents an HTML element.
Web Browser Operation Sequence
The browser parses HTML and constructs the DOM Tree -> Creates the Render Tree -> Layout the Render Tree -> Paints the Render Tree
- The DOM Tree is generated by the rendering engine when parsing the HTML document (e.g., WebKit).
- CSS is parsed and applied to the HTML to generate the Render Tree.
- The Render Tree is drawn onto the browser.
Whenever we change a node, all of the above happens again. The more frequently a node changes, the more load the browser receives to repaint the view. This becomes a very costly operation.
What Virtual DOM Solves
- Instead of immediately rendering the changes to the nodes, the changes are first applied to the Virtual DOM.
- Changes made to the Virtual DOM are not directly rendered to the view. This makes it a low-cost operation, similar to the difference between drawing blueprints for a new building and actually constructing the building.
- Additionally, Virtual DOM batches the changes for efficiency and applies them all at once.
Virtual DOM
Simply put, Virtual DOM is a tree-structured pure JavaScript object.
It is lightweight and exists in memory. It is never actually rendered. The idea of Virtual DOM was introduced by React but is now used in other front-end frameworks as well (e.g., Angular 2, Vue).
How React's Virtual DOM Works
- In the initial rendering process, JSX informs the template compiler how to create an in-memory DOM Tree.
- When
ReactDOM.render()
is called, the Virtual DOM Tree is created in memory.
Handling State Changes
- Most updates to the app are handled by the
setState
function.
- When state changes, the tree is completely re-created.
- This means two different Virtual DOMs will exist in memory when the state changes.
- While this may seem inefficient, it is not, as React Elements are very lightweight.
- React compares the two trees and maps the differences.
- It then creates a patch with the differences and applies them to the actual DOM.
- The diffing algorithm is used to find the minimum number of changes needed to update the actual DOM.
- These operations are batched so that the actual DOM is only updated once per lifecycle.
Diffing, or "Reconciliation"
- Finding the minimum number of changes has an
O(n^3)
complexity.
- React uses an
O(n)
approach.
- How? It relies on two assumptions.
Assumption 1
- Elements of different types create different trees.
- So, when React compares two different trees, it compares the root elements of each.
- If the root elements are of different types, React discards the old tree and replaces it with the new one, redrawing all subtrees under the root.
Assumption 2
- The
key
attribute helps detect changes in child elements.
- To improve performance, the
key
values should be stable, predictable, and unique.
<ul> <li>John</li> <li>Alice</li> </ul>
<ul> <li>John</li> <li>Alice</li> <li>Ed</li> </ul>
Without
key
values, even if a new child element is added, all child elements must be redrawn. However, if we use key
values to differentiate child elements, React can identify which elements need to be updated.<ul> <li key="9">John</li> <li key="10">Alice</li> <li key="11">Ed</li> </ul>
If the
key
value is randomly generated (e.g., using Math.random()
), React won't be able to predict and the child elements may not render correctly.What's Next?
React Fiber
React's new approach to rewriting its reconciliation algorithm. Instead of continuously cycling through the DOM, it uses a new data structure called fiber. Fiber is a pure JavaScript object that tracks the parent-child node relationship in a linked-list form. The tasks above are called "incremental rendering" or "scheduling."