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.
Component
Used to create the React component class.PureComponent
Used to create React pure component classes.createElement
Create the React element.cloneElement
Copy the React element.isValidElement
Determine if a React element is valid.PropTypes
Define the React props type. (Obsolete apis)createClass
Create the React component class (obsolete API).createFactory
Create the React factory function. (Not recommended).createMixin
Create a Mixin.DOM
Mainly related to isomorphism.version
The 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 API
React.createClass
Class inheritance is now recommended for developersComponent
orPureComponent
. - for
PropTypes
The 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
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
<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.
? type
React Element’s Symbol is of type Symbol.type
Type of the React element.key
The React key is used by the diff algorithm.ref
The React element’s ref attribute, which returns a reference to the DOM when the React element generates the actual DOM.props
The React element property is an object._owner
The 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
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!