This article was originally published by Axi (Hujiang Web Front-end development engineer).

Almost everyone who knows React has heard of Virtual DOM. Even people who don’t know React have heard of Virtual DOM. What does the React Virtual DOM look like? Today we’ll take a look at the React source code to uncover the React Virtual DOM.

The React stable version is v15.4.1.

1. React

Let’s first try printing React on the console to see what it looks like:

SRC /isomorphic/ react.js: SRC /isomorphic/ react.js: SRC /isomorphic/ react.js:

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,
};
Copy the code

React is really an Object. We can draw the React Object in the following form for intuitive observation:

React is an object that contains a number of methods and properties, including methods as recent as V15, older apis and deprecated apis.

  • ComponentUsed to create the React component class.
  • PureComponentUsed to create React pure component classes.
  • createElementCreate the React element.
  • cloneElementCopy the React element.
  • isValidElementDetermine if a React element is valid.
  • PropTypesDefine the React props type. (Obsolete apis)
  • createClassCreate the React component class (obsolete API).
  • createFactoryCreate the React factory function. (Not recommended).
  • createMixinCreate a Mixin.
  • DOMMainly related to isomorphism.
  • versionThe React version number in use.
  • __spread Have been abandonedDirect use,Object.assign()Instead of

The __spread method is deprecated and no longer recommended. At the time of this writing, React released version 15.5.0, in which createClass and PropTypes were also flagged as obsolete apis and would prompt warning.

  • For the old APIReact.createClassClass inheritance is now recommended for developersComponentorPureComponent.
  • forPropTypesThe introduction of “is not the original wayimport { PropTypes } from 'react'And becameimport PropTypes from 'prop-types'.

We won’t go into details about other properties and methods. This article will examine the react.createElement method, which is most closely related to creating the React Virtual DOM.

React. The createElement method method is invoked ReactElement ReactElement module. The createElement method method.

2. React Element

The Virtual DOM is a simulation of the real DOM, which is made up of real DOM elements, and the Virtual DOM is made up of Virtual DOM elements. We are already familiar with the actual DOM elements, which are HTML elements. So what are the virtual DOM elements? React gives the virtual DOM Element the name React Element.

React can combine HTML native elements into components that can then be reused by other components. So, both native elements and components are conceptually the same, reusable elements with specific functionality and UI. React therefore abstracts these elements into React elements. Whether it’s HTML native elements, such as

, , etc. Or combinations of these native elements (components), such as
, etc. They are React Elements, and the method to create these elements is react.createElement.

The React Virtual DOM is a tree made up of React elements.

Let’s explore what React Elements look like and how React elements are created.

2.1 ReactElement module

We’ll just print out

hello

:

We print
again, the structure of the App component is as follows:

<div>
	<h1>App</h1>
	<p>Hello world!</p>
</div>
Copy the code

The printed result looks like this:

The printed HTML Element is not a real DOM Element. The printed component is not a collection of DOM elements. All printed elements are one object, and they look very similar.

Then let’s look at the source section:

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,
  };
  if (__DEV__) {
    // ...
  }
  return element;
};
Copy the code

ReactElement is a factory function that takes seven arguments and returns a ReactElement object.

  • ? typeReact Element’s Symbol is of type Symbol.
  • typeType of the React element.
  • keyThe React key is used by the diff algorithm.
  • refThe React element’s ref attribute, which returns a reference to the DOM when the React element generates the actual DOM.
  • propsThe React element property is an object.
  • _ownerThe component responsible for creating the React element.

The self and source parameters are development-only parameters. From the above example, we can see that the only difference is type. For native elements, type is a string that records the type of the native element. For the React component, type is a constructor, or class, that records which class instance the React component is using. So
.type === App.

So, each wrapped React element is an object like this:

{
    ? typeof: REACT_ELEMENT_TYPE,
    type: type,
    key: key,
    ref: ref,
    props: props,
    _owner: owner,
}
Copy the code

Use a picture to represent the React Element like this:

2.2 ReactElement createElement method method

Before we do that, some might ask, we didn’t use the react. createElement method in our development. This is not the case, as shown in the following example:

class OriginalElement extends Component {
  render() {
    return (
      <div>Original Element div</div>); }}Copy the code

After Babel’s translation, it looks like this

_createClass(OriginalElement, [{
    key: "render".value: function render() {
      return React.createElement(
        "div".null."Original Element div"); }}]);Copy the code

As you can see, all JSX is compiled into the React. CreateElement method, so this is probably the most common method we use with React.

Then we look at the React. What is the createElement method method, said earlier the React. The createElement method method is actually ReactElement. The createElement method method.

ReactElement.createElement = function(type, config, children) {
  var propName;
  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 (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];
    }
    if (__DEV__) {
      // ...
    }
    props.children = childArray;
  }
  if (type && type.defaultProps) {
    var defaultProps = type.defaultProps;
    for (propName in defaultProps) {
      if (props[propName] === undefined) { props[propName] = defaultProps[propName]; }}}if (__DEV__) {
    // ...
  }
  return ReactElement(
    type,
    key,
    ref,
    self,
    source,
    ReactCurrentOwner.current,
    props
  );
};
Copy the code

ReactElement. The createElement method generally do two things.

The first is to initialize the various parameters in the React Element, such as type, props, and children. At initialization, the key and ref attributes are extracted, and the __self and __source attributes are also development-only. So if you define any of the key, ref, __self, and __source attributes in a component, you cannot access them in this.props. Starting with the third argument, all arguments passed in are merged into the children attribute. If there is only one, children is the third element, and if there is more than one, the elements are merged into a children array.

DefaultProps is initialized using Type. As we said earlier, for the React component, type is the class to which the React Element belongs. So you can use type to get defaultProps (the default property) for this class. Another thing to note here is that if we define a property as undefined, the default property is used for that property, but null does not use the default property.

Here is the illustration:

4. Create a Virtual DOM tree

With the above as a foundation, creating the Virtual DOM is simple. The entire Virtual DOM is a giant object.

For example, we have this App:

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

Header:
<div>
  <Logo />
  <button>The 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'))

Copy the code

The React Element creates a Virtual DOM that looks something like this:

It is important to note that these elements are not real DOM elements, they are just objects, and we can see that the React component is actually a conceptual form that eventually generates native virtual DOM objects. When the data on these objects changes, patch the changes to the real DOM.

For now, we can think of Virtual DOM as one of these forms, but in reality, it’s not that simple, it’s just a basic form, and I’ll take you through more advanced forms in a future article.

IKcamp’s original new book “Mobile Web Front-end Efficient Development Combat” has been sold on Amazon, JD.com and Dangdang


In 2019, iKcamp’s original new book Koa and Node.js Development Actual Combat has been sold on JD.com, Tmall, Amazon and Dangdang!