1. 创建调试源码项目
1.1 拉取React源码, 并创建调试项目,参考调试源码官方方式
1.2 删除调试项目多余的代码,将index.js作为入口改成如下,并在ReactDOM.createRoot处打断点
import React, {useState} from 'react';
import ReactDOM from 'react-dom/client';
const App = () => {
const [num, setNum] = useState(100);
return <div onClickCapture={() => setNum(num + 1)}>{num}</div>;
};
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<App />
);
图1-2-1
2. 启动调试源码项目,并断点调试
2.1 ReactDOM.createRoot方法,创建FiberRootNode, hostRootFiber
图2-1-1
断点进入到ReactDOM.createRoot内部,通过createFiberRoot方法,创建了root(对应下图FiberRootNode), uninitializedFiber(对应下图hostRootFiber)。并将root.current指向uninitializedFiber,uninitializedFiber.stateNode指向root。如下图的对应关系。
接下来执行initializeUpdateQueue方法,初始化了uninitializedFiber的updateQueue属性。
图2-1-2
2.2 root.render方法调用过程
2.2.1 编译阶段生成的运行时代码转换
如下图,<App />函数组件,由react-scripts内部的@babel/plugin-transform-react-jsx插件在编译阶段转换成jsxDEV方法自执行函数。(由于CRA内部使用的webpack, 融入了一些webpack编译代码)
/*#__PURE__*/ (0, react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(
App,
{},
void 0,
false,
{
fileName: _jsxFileName,
lineNumber: 11,
columnNumber: 5
},
undefined
)
图2-2-1
查看打包源文件,如下图。可以看出,jsxDEV方法对应的是isValidElementType方法
图2-2-2
断点进入isValidElementType方法,参数type为App函数编译后的结果
图2-2-3
最后转换成ReactElement类型
图2-2-4
2.2.2 root.render方法执行
接下来进入root.render内部,执行updateContainer方法
图2-2-5
updateContainer方法内部完成了创建update并插入到current(即hostRootFiber),执行调度函数scheduleUpdateOnFiber,接下来便进入到调度阶段。
图2-2-6