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.
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.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Hujiang Technology
We focus on the real-world challenges developers face, delivering authentic, practical content and a direct platform for technical networking among developers.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
