跳到主要内容

快速刷新

快速刷新是 React Native 的一项功能,可让你几乎即时地获得 React 组件更改的反馈。快速刷新默认启用,你可以在 React Native 开发者菜单 中切换“启用快速刷新”。启用快速刷新后,大多数编辑内容应会在一两秒内可见。

工作原理

  • 如果你编辑了一个只导出 React 组件的模块,快速刷新只会更新该模块的代码,并重新渲染你的组件。你可以编辑该文件中的任何内容,包括样式、渲染逻辑、事件处理程序或副作用。
  • 如果你编辑了一个导出内容_不是_ React 组件的模块,快速刷新会重新运行该模块以及导入它的其他模块。因此,如果 Button.jsModal.js 都导入了 Theme.js,编辑 Theme.js 会更新这两个组件。
  • 最后,如果你编辑的文件React 树之外的模块导入,快速刷新将退回为执行完整重新加载。你可能有一个文件,它渲染了一个 React 组件,但同时也导出一个被非 React 组件导入的值。例如,你的组件可能还导出一个常量,而某个非 React 工具模块导入了它。在这种情况下,考虑将该常量迁移到单独的文件中,并在两个文件中都导入它。这样就会重新启用快速刷新。其他情况通常也可以用类似方式解决。

错误恢复能力

如果你在快速刷新会话期间出现了语法错误,你可以修复它并再次保存文件。红色错误框会消失。带有语法错误的模块会被阻止运行,因此你不需要重新加载应用。

如果你在模块初始化期间发生了运行时错误(例如,把 Style.create 写成了 StyleSheet.create),一旦你修复错误,快速刷新会话将继续。红色错误框会消失,并且该模块会被更新。

如果你犯了一个导致组件内部运行时错误的错误,快速刷新会话在你修复错误后也会_继续_。在这种情况下,React 将使用更新后的代码重新挂载你的应用。

如果你的应用中有错误边界(这对于生产环境中的优雅失败是个好主意),它们会在红色错误框出现后,于下一次编辑时重试渲染。从这个意义上说,使用错误边界可以避免你总是被踢回根应用屏幕。不过,请记住,错误边界不应该过于细粒度。它们在生产中由 React 使用,并且应始终经过深思熟虑地设计。

限制

快速刷新会尝试保留你正在编辑的组件中的本地 React 状态,但前提是这样做是安全的。以下是你在每次编辑文件时可能看到本地状态被重置的一些原因:

  • 类组件不会保留本地状态(只有函数组件和 Hooks 会保留状态)。
  • 你正在编辑的模块除了 React 组件之外,可能还有_其他_导出。
  • 有时,一个模块会导出调用高阶组件的结果,例如 createNavigationContainer(MyScreen)。如果返回的组件是类组件,状态将会被重置。

从长远来看,随着你的代码库越来越多地迁移到函数组件和 Hooks,你可以期待在更多情况下保留状态。

提示

  • 默认情况下,快速刷新会在函数组件(以及 Hooks)中保留 React 本地状态。
  • 有时你可能想要_强制_重置状态,并让组件重新挂载。例如,如果你正在调整一个只在挂载时发生的动画,这会很方便。为此,你可以在正在编辑的文件中的任意位置添加 // @refresh reset。这个指令仅对当前文件有效,并会指示快速刷新在每次编辑时重新挂载该文件中定义的组件。

快速刷新和 Hooks

在可能的情况下,快速刷新会尝试在编辑之间保留组件的状态。特别是,只要你不更改 useStateuseRef 的参数或 Hook 调用顺序,它们就会保留之前的值。

带有依赖项的 Hooks——例如 useEffectuseMemouseCallback——在快速刷新期间将_始终_更新。快速刷新进行时,它们的依赖项列表会被忽略。

例如,当你把 useMemo(() => x * 2, [x]) 编辑为 useMemo(() => x * 10, [x]) 时,即使 x(依赖项)没有变化,它也会重新运行。如果 React 不这样做,你的更改就不会反映在屏幕上!

有时,这可能会导致意外结果。例如,即使是依赖项为空数组的 useEffect,在快速刷新期间也仍然会重新运行一次。不过,即使没有快速刷新,编写能承受偶尔重新运行 useEffect 的代码也是一种好习惯。这会让你以后更容易为它引入新的依赖项。