我们假定你对react有一定的了解会应用react,且看过官方文档。此处使用的react和react-dom版本是:16.7.0。
使用creat-react-app创建一个App,并启动。
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
class App extends Component {
render() {
return (<div id='appId'>Hello World!</div>);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
在执行这段代码时,ReactDOM.render中的
将App换为div,修改代码为:
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
ReactDOM.render(<div id='appId'>Hello World!</div>, document.getElementById('root'));
在执行这段代码时,ReactDOM.render中的’

在react的世界里,不论 div 还是 App 都是react.element,转换后的都带有各自的身份type。无论身份身份相同,初始处理的方式都相似。
ReactElement
ReactElement的格式如下:
// packages\shared\ReactElementType.js
export type Source = {
fileName: string,
lineNumber: number,
};
export type ReactElement = {
$$typeof: any,
type: any,
key: any,
ref: any,
props: any,
_owner: any, // ReactInstance or ReactFiber
// __DEV__
_store: {
validated: boolean,
},
_self: React$Element<any>,
_shadowChildren: any,
_source: Source,
};
div等 和 Component都是ReactElement,值不同而已。
Render
react-dom是react的一个渲染器。按React设计思路,react-dom是提供针对DOM的方法。
var ReactDOM = {
render: function render(element, container, callback) {
return legacyRenderSubtreeIntoContainer(null, element, container, false, callback);
}
}
在调用 ReactDOM.render 时,第一个参并不是根元素。使用ReactDOM.render时,调用的是 legacyCreateRootFromDOMContainer 。在legacyCreateRootFromDOMContainer 中会根据root的有无,判断当前所在的阶段。若无 root 是Initial mount,有root则是 Update。在Initial mount阶段,legacyCreateRootFromDOMContainer 会返回 ReactRoot 实例。
function legacyRenderSubtreeIntoContainer(
parentComponent: ?React$Component<any, any>,
children: ReactNodeList,container: DOMContainer,forceHydrate: boolean,callback: ?Function
) {
let root: Root = (container._reactRootContainer: any);
if (!root) {
// Initial mount
root = container._reactRootContainer = legacyCreateRootFromDOMContainer( container,
forceHydrate,
);
if (typeof callback === 'function') {
const originalCallback = callback;
callback = function() {
const instance = getPublicRootInstance(root._internalRoot);
originalCallback.call(instance);
};
}
// Initial mount should not be batched.
unbatchedUpdates(() => {
if (parentComponent != null) {
root.legacy_renderSubtreeIntoContainer(parentComponent,children,callback);
} else {
root.render(children, callback);
}
});
} else {
if (typeof callback === 'function') {
const originalCallback = callback;
callback = function() {
const instance = getPublicRootInstance(root._internalRoot);
originalCallback.call(instance);
};
}
// Update
if (parentComponent != null) {
root.legacy_renderSubtreeIntoContainer(parentComponent,children,callback);
} else {
root.render(children, callback);
}
}
return getPublicRootInstance(root._internalRoot);
}
function legacyCreateRootFromDOMContainer(container: DOMContainer,forceHydrate: boolean) {
//...
const isConcurrent = false;
return new ReactRoot(container, isConcurrent, shouldHydrate);
}
在legacyCreateRootFromDOMContainer中会创建ReactRoot实例,在创建ReactRoot实例时会创建 FiberRoot(ReactRoot中createContainer创建),FiberRoot用于记录着这棵树的信息。请看在官网查看ReactRoot的具体代码。
ReactRoot的实例
其中current是 createHostRootFiber -> createFiber(HostRoot, null, null, mode); 此时的mode值为4。
ReactRoot.render
root.render 其实是ReactRoot.render,用于渲染整棵树,代码如下:
ReactRoot.prototype.render = function (children, callback) {
var root = this._internalRoot;
var work = new ReactWork();
callback = callback === undefined ? null : callback;
if (callback !== null) {
work.then(callback);
}
updateContainer(children, root, null, work._onCommit);
return work;
};
updateContainer 开始渲染ReactRoot。