本指南帮助你在使用 React 编译器时识别并修复问题。了解如何调试编译问题并解决常见问题。
You will learn
- 编译器错误与运行时问题之间的区别
- 会破坏编译的常见模式
- 分步骤的调试工作流程
理解编译器行为
React 编译器旨在处理符合 React 规则 的代码。当它遇到可能违反这些规则的代码时,它会安全地跳过优化,而不是冒着改变应用行为的风险。
编译器错误 vs 运行时问题
编译器错误 发生在构建时,会阻止代码编译。这类错误很少见,因为编译器的设计是跳过有问题的代码,而不是直接失败。
运行时问题 发生在编译后的代码表现与预期不同的时候。大多数情况下,如果你遇到 React 编译器相关的问题,那通常是运行时问题。这通常发生在你的代码以编译器无法检测到的微妙方式违反了 React 规则,而编译器错误地编译了一个本应跳过的组件。
在调试运行时问题时,请重点查找受影响组件中未被 ESLint 规则检测到的 React 规则违反情况。编译器依赖你的代码遵循这些规则;当这些规则以它无法检测的方式被破坏时,就会出现运行时问题。
常见的破坏模式
React 编译器可能破坏你的应用的一个主要方式,是你的代码是以依赖记忆化来保证正确性的方式编写的。这意味着你的应用依赖某些特定值被记忆化后才能正常工作。由于编译器的记忆化方式可能与你手动的做法不同,这可能导致意外行为,例如 effect 过度触发、无限循环或更新缺失。
会发生这种情况的常见场景包括:
- 依赖引用相等性的 effect - 当 effect 依赖对象或数组在多次渲染之间保持相同引用时
- 需要稳定引用的依赖数组 - 当不稳定的依赖导致 effect 触发过于频繁或产生无限循环时
- 基于引用检查的条件逻辑 - 当代码使用引用相等性检查进行缓存或优化时
调试工作流程
遇到问题时,请按以下步骤操作:
编译器构建错误
如果你遇到一个意外破坏构建的编译器错误,这很可能是编译器中的 bug。请将它报告到 facebook/react 仓库,并附上:
- 错误消息
- 导致错误的代码
- 你的 React 和编译器版本
运行时问题
对于运行时行为问题:
1. 临时禁用编译
使用 "use no memo" 来隔离问题是否与编译器有关:
function ProblematicComponent() {
"use no memo"; // 跳过此组件的编译
// ... 组件其余部分
}如果问题消失了,那很可能与 React 规则违反有关。
你也可以尝试从有问题的组件中移除手动记忆化(useMemo、useCallback、memo),以验证在没有任何记忆化的情况下你的应用是否能正确工作。如果在移除所有记忆化后问题仍然存在,那么你就有一个需要修复的 React 规则违反问题。
2. 逐步修复问题
- 找出根本原因(通常是为了正确性的记忆化)
- 每修复一步后进行测试
- 修复完成后移除
"use no memo" - 验证该组件在 React DevTools 中显示 ✨ 徽标
报告编译器 bug
如果你认为自己发现了编译器 bug:
- 确认这不是 React 规则的违反 - 使用 ESLint 检查
- 创建最小可复现示例 - 在一个小例子中隔离问题
- 在没有编译器的情况下测试 - 确认问题只在启用编译时发生
- 提交一个 issue:
- React 和编译器版本
- 最小可复现代码
- 预期行为与实际行为
- 任何错误消息