跳到主要内容

快速刷新

快速刷新是 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)中的本地状态。
  • 有时候你可能想_强制_重置状态,重新挂载组件。例如,如果你正在调整只在挂载时发生的动画,这很有用。为此,你可以在编辑的文件中任意位置添加 // @refresh reset。该指令仅对所在文件生效,指示快速刷新在每次编辑时重新挂载该文件中定义的组件。

快速刷新与 Hooks

快速刷新尽可能在编辑间保留组件的状态。特别是,只要你不改变其参数或 Hook 调用顺序,useStateuseRef 会保留之前的值。

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

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

有时这会导致意外结果。例如,即使是依赖项为空数组的 useEffect,快速刷新时也会重新执行一次。然而,即使没有快速刷新,编写能适应 useEffect 偶尔重新运行的代码也是良好实践。这让你将来更容易向其中添加新依赖。