我们假定你对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.jsexport 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 mountroot = 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);};}// Updateif (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。
