Virtual DOM Diffing
Virtual DOM diffing is the process by which JavaScript frameworks like React compare a new in-memory tree of UI description objects against the previous tree to determine the minimal set of real DOM mutations required to bring the page up to date.
Virtual DOM diffing is the process by which JavaScript frameworks like React compare a new in-memory tree of UI description objects against the previous tree to determine the minimal set of real DOM mutations required to bring the page up to date.
The core insight is that real DOM mutations are expensive: each write can trigger style recalculation, layout, and paint (see DOM Update Lifecycle). By maintaining a lightweight JavaScript object representation of the UI — the virtual DOM — the framework can perform comparisons entirely in memory at the cost of JavaScript execution rather than browser rendering. Only the differences (the diff) are applied to the actual DOM.
When a component's state or props change, the framework calls the component's render function to produce a new virtual DOM tree. It then runs the reconciliation algorithm to compare the new tree against the previous virtual DOM snapshot. React's reconciler uses a heuristic O(n) algorithm rather than the theoretically optimal O(n³) tree-edit-distance algorithm, because the optimal approach is too slow for real-time UIs. The key heuristics are: two elements of different types produce completely different trees (the old subtree is unmounted and a new one mounted); elements of the same type are updated in place; and key props on list items allow the reconciler to match nodes across positions without re-mounting them. This is why missing or unstable key values cause list performance issues.
Once the diff is computed, the framework generates a patch — a list of DOM operations such as setAttribute, removeChild, appendChild, and textContent updates. These are applied in a single batch, minimizing forced synchronous layouts. Libraries like Inferno and Preact use similar vdom diffing strategies with different performance tradeoffs.
Understanding diffing explains why React.memo, shouldComponentUpdate, and useMemo matter: they short-circuit the render phase entirely when inputs haven't changed, preventing even the virtual DOM work. See React Rendering Lifecycle for where these optimizations hook in.