想要深入学习React底层知识,充实自己(为了面试~),还是得看看源码才有底气。推荐一个国外小哥的博客&视频:React Internals Deep Dive。不过磨刀不误砍柴工,在正式开始前,我们得看看如何调试React源码。
准备工作
调试前我们需要先准备好调试使用的代码。有两种方式:从源码构建(推荐)或使用已发布的React包。
从源码构建
参考React官方文档:development-workflow。
shell
# 克隆
$ git clone https://github.com/facebook/react.git
# 安装依赖
$ cd react & yarn
# 构建
$ yarn build react/index,react-dom/index --type=UMD
构建完成后,打开fixtures/packaging/babel-standalone/dev.html文件,其中引用的即是刚才构建好的React。
html
<html>
<body>
<script src="../../../build/oss-experimental/react/umd/react.development.js"></script>
<script src="../../../build/oss-experimental/react-dom/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.js"></script>
<div id="app"></div>
<script type="text/babel">
const container = document.getElementById('app');
const root = ReactDOM.createRoot(container);
root.render(<h1>Hello World!</h1>);
</script>
</body>
</html>;
解释下代码里的"text/babel":babel会在DOM加载完成时检测"text/babel"类型的脚本,并转换代码后执行,从而支持直接编写JSX。sricpt
标签类型为type="text/babel"
时,其内部代码是不会被浏览器执行的。
使用已发布的React包
只需将React链接修改为已发布的链接即可。
html
<html>
<body>
<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/babel-standalone@6/babel.js"></script>
<div id="app"></div>
<script type="text/babel">
const container = document.getElementById('app');
const root = ReactDOM.createRoot(container);
debugger;
root.render(<h1>Hello World!</h1>);
</script>
</body>
</html>;
开始调试
在准备好代码之后,我们就可以着手开始调试了。调试可以用浏览器(推荐Chrome)开发者工具,也可以用VSCode,选择个人熟悉的即可,也可以各取所长。
浏览器开发者工具
在调试前,我们可以通过开发者工具的Performance面板查看完整的运行过程。效果如下:
点击函数可以查看源码位置:
下一步我们即可以在Sources面板的源码中打断点调试。
或者直接在代码中添加debugger
:
jsx
const container = document.getElementById('app');
const root = ReactDOM.createRoot(container);
debugger; // 程序将停止在这里
root.render(<h1>Hello World!</h1>);
VSCode
VSCode也支持调试网页代码。第一步在左侧调试面板中点击新建launch.json文件,内容如下,将url改为网页地址或文件地址即可。
接着在react-dom.development.js文件中打上断点。
最后一步,点击左侧调试面板的Start Debugging启动调试。
一些调试小技巧
一般调试都有这几个按钮,以VSCode为例:
- Continue。前往下一个断点。
- Step Over 。一次执行完一条语句 。比如执行一个函数
const num = Math.sqrt(2,2)
,如果你不想进入Math.sqrt
里查看细节,只想看到执行完的结果,那么就用Step Over。反之,如果你想看Math.sqrt
里是如何实现的,则点击下面的Step Into。 - Step Into 。将会进入函数,一行一行执行。比如
const num = Math.sqrt(2,2)
,点击Step Into后点会进入到Math.sqrt
内部。 - Step Out。与Step Into对应。执行后将会跳出当前执行的函数。
- Restart。终止当前程序执行并重启调试。
- Stop。终止当前程序执行。
下面是一些常用的提高调试效率的小技巧:
善用Step Over
不是每个地方都需要Step Into来一行一行的调试,这时候使用Step Over,省略过程,快速获取结果就行。
遇到回调函数怎么办?
对于回调函数这种异步代码,我们无法通过Step Over或Step Into来跳转到指定处执行。
csharp
this.hooks.beforeCompile.callAsync(params, err => {
// 把断点打在回调函数里,点击Continue!
const compilation = this.newCompilation(params);
// ...
});
这时只需直接将断点打在回调函数里,点击Continue(前往下一个断点)即可。
不小心错过了想要调试的那一行?
直接将断点打在前面想要调试的那一行,点击Restart。
如何查看调用栈?
如果一个程序逻辑比较绕,回调比较多,梳理不清楚执行过程,可以查看调用栈来帮助分析。