启动过程
React 应用启动的 3 种模式
在当前稳定版react@17.0.2
源码中, 有 3 种启动方式. 先引出官网上对于这 3 种模式的介绍, 其基本说明如下:
-
legacy
模式:ReactDOM.render(<App />, rootNode)
. 这是当前 React app 使用的 方式. 这个模式可能不支持这些新功能(concurrent 支持的所有功能).// LegacyRoot
ReactDOM.render(<App />, document.getElementById('root'), (dom) => {}); // 支持callback回调, 参数是一个dom对象 -
Blocking 模式:
ReactDOM.createBlockingRoot(rootNode).render(<App />)
. 目前正在实验中, 它仅提供了concurrent
模式的小部分功能, 作为迁移到concurrent
模式的第一个步骤.// BlockingRoot
// 1. 创建ReactDOMRoot对象
const reactDOMBlockingRoot = ReactDOM.createBlockingRoot(
document.getElementById('root'),
);
// 2. 调用render
reactDOMBlockingRoot.render(<App />); // 不支持回调 -
Concurrent 模式:
ReactDOM.createRoot(rootNode).render(<App />)
. 目前在实验中, 未来稳定之后,打算作为 React 的默认开发模式. 这个模式开启了所有的新功能.// ConcurrentRoot
// 1. 创建ReactDOMRoot对象
const reactDOMRoot = ReactDOM.createRoot(document.getElementById('root'));
// 2. 调用render
reactDOMRoot.render(<App />); // 不支持回调
创建全局对象
无论Legacy, Concurrent或Blocking
模式, react 在初始化时, 都会创建 3 个全局对象
- 属于
react-dom
包, 该对象暴露有render,unmount
方法, 通过调用该实例的render
方法, 可以引导 react 应用的启动.
-
- 属于
react-reconciler
包, 作为react-reconciler
在运行过程中的全局上下文, 保存 fiber 构建过程中所依赖的全局状态. - 其大部分实例变量用来存储
fiber 构造循环
(详见两大工作循环
)过程的各种状态.react 应用内部, 可以根据这些实例变量的值, 控制执行逻辑.
- 属于
-
- 属于
react-reconciler
包, 这是 react 应用中的第一个 Fiber 对象, 是 Fiber 树的根节点, 节点的类型是HostRoot
.
- 属于
这 3 个对象是 react 体系得以运行的基本保障, 一经创建大多数场景不会再销毁(除非卸载整个应用root.unmount()
).
在创建HostRootFiber
时, 其中fiber.mode
属性, 会与 3 种RootTag
(ConcurrentRoot
,BlockingRoot
,LegacyRoot
)关联起来.
export function createHostRootFiber(tag: RootTag): Fiber {
let mode;
if (tag === ConcurrentRoot) {
mode = ConcurrentMode | BlockingMode | StrictMode;
} else if (tag === BlockingRoot) {
mode = BlockingMode | StrictMode;
} else {
mode = NoMode;
}
return createFiber(HostRoot, null, null, mode); // 注意这里设置的mode属性是由RootTag决定的
}
注意:fiber
树中所有节点的mode
都会和HostRootFiber.mode
一致(新建的 fiber 节点, 其 mode 来源于父节点),所以HostRootFiber.mode非常重要, 它决定了以后整个 fiber 树构建过程.