Exploring React's Virtual DOM: Source Code Analysis

This article examines React's Virtual DOM by dissecting the React source code, explaining the structure of the React object, ReactElement factory, the createElement implementation, and how these pieces combine to build a virtual DOM tree for rendering components.

Hujiang Technology
Hujiang Technology
Hujiang Technology
Exploring React's Virtual DOM: Source Code Analysis

Most React developers have heard of the Virtual DOM, but few have seen its actual implementation. This article walks through the React stable source (v15.4.1) to reveal how the Virtual DOM is constructed.

1. React Object

Printing React in the console shows that it is an object. The source file src/isomorphic/React.js defines the object with properties such as Component, PureComponent, createElement, cloneElement, isValidElement, PropTypes (deprecated), createClass (deprecated), createFactory (discouraged), createMixin, DOM, version, and __spread (deprecated).

var React = {
  Children: {
    map: ReactChildren.map,
    forEach: ReactChildren.forEach,
    count: ReactChildren.count,
    toArray: ReactChildren.toArray,
    only: onlyChild,
  },
  Component: ReactComponent,
  PureComponent: ReactPureComponent,
  createElement: createElement,
  cloneElement: cloneElement,
  isValidElement: ReactElement.isValidElement,
  PropTypes: ReactPropTypes,
  createClass: ReactClass.createClass,
  createFactory: createFactory,
  createMixin: function(mixin) { return mixin; },
  DOM: ReactDOMFactories,
  version: ReactVersion,
  __spread: __spread,
};

The object also contains legacy APIs that are now discouraged or deprecated, such as createClass, PropTypes, and __spread. Modern code should use ES6 classes ( Component or PureComponent) and import prop-types separately.

2. React Element

Virtual DOM elements are represented by React Elements. Both native HTML tags (e.g., <p>, <a>) and custom components (e.g., <Message/>) become React Elements created via React.createElement.

React Virtual DOM is a tree composed of React Elements.

2.1 ReactElement Module

Printing a JSX element like <h1>hello</h1> or a component <App/> in the console shows an object rather than a real DOM node. The source defines the factory function:

var ReactElement = function(type, key, ref, self, source, owner, props) {
  var element = {
    $$typeof: REACT_ELEMENT_TYPE,
    type: type,
    key: key,
    ref: ref,
    props: props,
    _owner: owner,
  };
  return element;
};

The element contains fields such as $$typeof (a Symbol), type, key, ref, props, and _owner. The type is a string for native elements or a constructor/class for component elements.

2.2 ReactElement.createElement

All JSX is compiled to React.createElement. The implementation performs two main tasks: initializing the element’s fields (including extracting key, ref, __self, __source) and applying defaultProps from the component type.

ReactElement.createElement = function(type, config, children) {
  var props = {};
  var key = null;
  var ref = null;
  var self = null;
  var source = null;
  if (config != null) {
    if (hasValidRef(config)) { ref = config.ref; }
    if (hasValidKey(config)) { key = '' + config.key; }
    self = config.__self === undefined ? null : config.__self;
    source = config.__source === undefined ? null : config.__source;
    for (var propName in config) {
      if (hasOwnProperty.call(config, propName) && !RESERVED_PROPS.hasOwnProperty(propName)) {
        props[propName] = config[propName];
      }
    }
  }
  var childrenLength = arguments.length - 2;
  if (childrenLength === 1) {
    props.children = children;
  } else if (childrenLength > 1) {
    var childArray = Array(childrenLength);
    for (var i = 0; i < childrenLength; i++) {
      childArray[i] = arguments[i + 2];
    }
    props.children = childArray;
  }
  if (type && type.defaultProps) {
    var defaultProps = type.defaultProps;
    for (var propName in defaultProps) {
      if (props[propName] === undefined) {
        props[propName] = defaultProps[propName];
      }
    }
  }
  return ReactElement(type, key, ref, self, source, ReactCurrentOwner.current, props);
};

Key points: key and ref are not accessible via this.props; children can be a single element or an array; defaultProps are merged when a prop is undefined but not when it is null.

4. Building the Virtual DOM Tree

Using the element creation rules, a component hierarchy such as App → Header → Logo/List is transformed into a large nested object representing the Virtual DOM. The tree consists solely of React Element objects, not real DOM nodes, and is later reconciled with the actual DOM via patches.

App:
<div>
  <Header />
  <List />
</div>

Header:
<div>
  <Logo />
  <button>Menu</button>
</div>

List:
<ul>
  <li>text 1</li>
  <li>text 2</li>
  <li>text 3</li>
</ul>

Logo:
<div>
  <img src="./foo.png" alt="logo" />
  <p>text logo</p>
</div>

ReactDOM.render(<App />, document.getElementById('root'));

The resulting Virtual DOM is a tree of objects that mirrors the component structure; when data changes, React computes a diff and patches the real DOM accordingly.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaScriptReactVirtual DOMReactElement
Hujiang Technology
Written by

Hujiang Technology

We focus on the real-world challenges developers face, delivering authentic, practical content and a direct platform for technical networking among developers.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.