Mechanics of React's VDOM

devfish·2023년 3월 22일
0

React

목록 보기
9/10

Key Points

  • (Why DOM?) Tree structure: very easy to search and approach!
  • Because it's easy... might be tempting to frequently update the DOM, but this is very expensive in terms of performance
  • Diffing uses a BFS type traversal method to compare old vs new virtual DOM.
  • DFS type recursion-based method is used for implementing batch updates? or batching the updates? I'm really confused...

How It Works

  • Using a virtual DOM minimizes DOM manipulation/updates and optimizes performance by only updating nodes that need to be updated. React achieves this by comparing its initial virtual copy of the DOM (pristine v.) with its updated copy of the DOM (dirty v), and updates the changes (reconciling its differences) in the actual DOM using its diffing algorithm (i.e. synchronizes the old DOM tree to match the updated virtual DOM tree by libraries like ReactDOM, which accordingly updates all affected elements on the screen)

    • A new virtual DOM is created (dirty v) on every re-render
    • VDOM is only an abstract representation of the real DOM, hence very lightweight. It has all the properties of the actual DOM, without any actual power in and of itself to actually update what we see on the screen
    • "Diffing is accomplished by a heuristic O(n) algorithm. During this process, React will deduce the minimum number of steps needed to update the real DOM, eliminating unnecessary costly changes" (link)
  • Batch Updates: React checks all the elements that need updating then batch updates them (as in the updates are sent as a batch to actual DOM to re-render/re-paint the UI) in one go. Avoiding frequent updates of the DOM improves performance

  • Sub-Tree Rendering: when setState is called, the component rebuilds the virtual DOM, then compares this DOM with the previous DOM ('diffing') - and only changes the different objects in the real DOM (and tries to find the most efficient way to do so.) This minimizes operations on the real DOM, thus reducing performance costs.

    • Every state change re-renders the whole sub-tree, so if you want to optimize performance, call it only when absolutely necessary and prevent re-rendering the whole sub-tree with shouldComponentUpdate.

      • You can be selective about which sub-trees to re-render by using shouldComponentUpdate(Official Ref, Explanation)
    • When we say a state change triggers a 're-rendering' of a component- this does not mean any changes were made in the actual DOM - if the output of the render was the same was before, React does nothing. (1)

  • Q: But if adding a list element, for instance, updates the entirety of how that list is displayed (for instance, when it's added on the top) - doesn't the state that is managed on a parent element trigger a re-rendering of all its children elements anyway? Even if it's just the renaming of an individual list item, isn't that also managed on the parent element, and any state changes triggers a re-rendering? Or.. does it mean diffing algo differentiates which necessitates the UI/display to be updated, and which don't? (value changes)

Two elements of different types will produce different trees

e.g. if div changes to span, redraw the tree!

The critical function of the key attribute in React

Unique keys among siblings are how React identifies which exact element was updated in rendering list items. It is integral to how React makes correct updates to the actual DOM tree, and isolates which elements need re-rendering and which do not.

  • React strongly recommends against using index in an array as a key (which is what it defaults to when not specified), since this mapping will get mixed up when items are re-sorted, inserted, deleted etc., which can lead to all sorts of confusing bugs and negatively affect performance.

  • Randomly generating keys on the fly would also cause the keys to conflict with each other betwen renders, triggering the components and DOM to be re-created each time (any user input will also be lost)

  • The keys only need to be differentiated from its siblings, not globally unique

Calculating its Efficiency

Without React, a difference in node trees can be calculated by O(n³), which means that 1,000 operations would require 1,000,000 calculations. Because of the diffing algorithm, React can calculate differences at a rate of O(n). (quote/imgs below lifted from this link)

+Concepts

Shadow DOM

  • "The Shadow DOM is a browser technology designed primarily for scoping variables and CSS in web components."
  • "It’s a separate and isolated DOM for an element. It’s used to keep the markup structure, style, and behavior hidden and separated from other code on the page so that different parts do not clash and the code can be kept nice and clean." (link)

Why should one use the shadow DOM approach in React?

If you render React element(s) inside a shadow DOM, the React element(s) won’t inherit any styles from the page CSS. For example, a third-party plugin that overlays some UI on top of a page would use a shadow DOM to prevent its UI from being affected by any page style.

React Fiber

Fiber is the new reconciliation engine in React 16. Its main goal is to enable incremental rendering of the virtual DOM. (Click here for official documentation, and here for a deep dive into how it changed the game)

References

React Virtual DOM vs Real DOM
What is the virtual DOM in React?
Shadow Dom vs. Virtual Dom
Virtual DOM vs. Shadow DOM: What Every Developer Should Know
Render React element inside shadow DOM in React v18

React’s Diffing Algorithm
React’s diff algorithm: 2013 by FB SW Engineer
KR Ref: 리액트는 어떻게 작동할까 : Diffing
React 적용 가이드 - React 작동 방법

Why do I need Keys in React Lists?

When does React re-render components?
How to check if your component rerendered - and why!

profile
la, di, lah

0개의 댓글