react学习14:如何调试react

35 阅读5分钟

什么是调试?

代码在某个平台运行,把运行时的状态通过某种方式暴露出来,传递给开发工具做 UI 的展示和交互,辅助开发者排查问题、梳理流程、了解代码运行状态等,这个就是调试。

这里的某个平台,可以是浏览器、Node.js、Electron、小程序等任何能执行 JS 代码的平台。

暴露出的运行时状态,可能是调用栈、执行上下文,或者 DOM 的结构,React 组件的状态等。

暴露出这些数据的方式一般是通过基于 WebSocket 的调试协议,当然也会有别的方式。

调试网页,我们一般用用 Chrome DevTools,可以查看元素,网络请求,断点运行 JS,用 Performance 工具分析性能等。

Chrome DevTools 分为两部分,backend 和 frontend:

  • backend 和 Chrome 集成,负责把 Chrome 的网页运行时状态通过调试协议暴露出来。
  • frontend 是独立的,负责对接调试协议,做 UI 的展示和交互。

两者之间的调试协议叫做 Chrome DevTools Protocol,简称 CDP。

传输协议数据的方式叫做信道(message channel),有很多种,比如 Chrome DevTools 嵌入在 Chrome 里时,两者通过全局的函数通信;当 Chrome DevTools 远程调试某个目标的代码时,两者通过 WebSocket 通信。

frontend、backend、调试协议(CDP)、信道,这是 Chrome DevTools 的 4 个组成部分。

image.png

react 调试

我们以 React 项目为例,用 vite 创建一个 react 项目:

进入项目目录,执行 npm run dev, 启动项目,打开 Chrome DevTools,在 Sources 面板找到 src/main.tsx,打上个断点:

image.png

然后刷新就可以开始调试了。

其实调试网页的 JS,除了 Chrome DevTools 外,还有一种更好用的调试方式: VSCode Debugger。

用 VSCode 打开项目目录,创建 .vscode/launch.json 文件,点击右下角的 Add Configuration... 按钮,选择 Chrome: Launch

image.png

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "chrome",
      "request": "launch",
      "name": "Launch Chrome against localhost",
      "url": "http://localhost:5173",
      "webRoot": "${workspaceFolder}"
    }
  ]
}
  1. 确保 Vite 开发服务已启动(npm run dev 不关闭),把launch.json的 url 改为开发服务器启动的地址:http://localhost:5173。

launch 它仅表示 “启动调试器并打开指定的浏览器 / 应用”,但不会自动启动你的前端开发服务器(Vite、Webpack 等)。调试器(vscode debugger)只是 “连接” 到已运行的浏览器,而非 “启动” 前端服务器。

所以,我们还需要执行npm run dev来启动服务。当启动调试的时候,它会另外打开一个chrome浏览器窗口用于调试。

  1. 在 VS Code 中打开 React 组件文件(如 src/App.jsx),点击代码行号左侧添加断点(红色圆点)。

  2. 点击调试面板的启动调试按钮(绿色三角),VS Code 会自动打开 Chrome 并访问 http://localhost:5173

这样就可以使用vscode进行调试了。

不过,有同学可能会问,这个浏览器好像没有 React DevTools 啊。

确实,因为这跑的是一个新的浏览器实例,没有之前的那些用户数据。

用户数据是保存在 userDataDir 里的,一个 userDataDir 对应一个浏览器实例。

不信我们试试看:

image.png

我指定一个 userDataDir,然后点击调试启动。

在启动的浏览器里把掘金收藏为书签:

然后进入刚才那个 userDataDir,进入 defaults 目录,看一下 Bookmarks 文件的内容:

image.png

image.png

就有刚才保存的书签了。

同理,各种 chrome 插件、浏览记录、cookies 等等,所有用户数据都是保存在 userDataDir 里。

image.png

chrome 一个 userDataDir 只能跑一个实例。

我们调试的时候,如果没有指定 userDataDir,默认是临时创建一个新的 userDataDir。

所以这时候自然就没有 React DevTools 等你之前安装的插件了。

如果想调试的时候还用这些插件,那可以把 userDataDir 设置为 false,就是这样就是用默认的 userDatDir 来跑:

"userDataDir": false

这时候需要你把之前跑的 chrome 关掉才能跑,因为一个 userDataDir 只能跑一个实例。否则会报错:

image.png

之后再点击调试,这次跑的浏览器就有你之前装的 React DevTools 了。

结合 click-to-react-component 打造超级爽的 React 调试体验

如果说业务开发中最重要的能力,那定位代码的能力肯定是其中之一。

业务项目一般代码都很多,你拿到一个需求之后,可能改起来不难,但是要定位在哪里改比较难。

特别是接手别人写的代码的时候。

大家都是怎么在不熟悉的项目里定位的代码呢?

很多人都是搜文案,搜 className。

这样没问题,但如果你用了 styled-component 之类的方案之后,className 都是动态生成的。

而且不少项目都做了国际化,你搜文案会搜到资源包里,而不是组件代码里。

那有什么好的办法可以快速定位代码么?

有,就是 click-to-react-component。

我们创建个项目后,引入:

npm install --save-dev click-to-react-component

在 main.tsx 引入下:

import { ClickToComponent } from 'click-to-react-component'

createRoot(document.getElementById('root')!).render(
  // <StrictMode>
  <Provider store={store}>
    {import.meta.env.DEV && <ClickToComponent />}
    <App />
  </Provider>
  // </StrictMode>
)

可以看到,现在按住 alt + 单击,就会直接打开它的对应的组件的源码。

image.png

如果按住 option + 右键单击,可以看到它的所有父级组件,然后选择一个组件打开:

image.png

这样在页面上看到了啥东西就可以直接打开它的组件代码来改,特别高效。