快速刷新 (Fast Refresh)

快速刷新 (Fast Refresh) 是 Next.js 的一项功能,可即时反馈您对 React 组件所做的编辑。在 9.4 或更新版本 的所有 Next.js 应用程序中,快速刷新默认启用。启用 Next.js 快速刷新后,大多数编辑内容应在 不丢失组件状态 的情况下 一秒内可见

工作原理

  • 如果您编辑 仅导出 React 组件 的文件,快速刷新将仅更新该文件的代码并重新渲染您的组件。您可以编辑该文件中的任何内容,包括样式、渲染逻辑、事件处理程序或副作用。
  • 如果您编辑包含 React 组件导出的文件,快速刷新将重新运行该文件及其导入该文件的其他文件。例如,如果 Button.jsModal.js 都导入了 theme.js,编辑 theme.js 将更新这两个组件。
  • 最后,如果您编辑 被 React 树之外的文件导入 的文件,快速刷新 将回退到完全重新加载。您可能有一个文件既渲染 React 组件,又导出一个被 非 React 组件 导入的值。例如,您的组件可能还导出一个常量,而非 React 工具文件导入了它。在这种情况下,考虑将该常量迁移到单独的文件中,并在两个文件中导入它。这将重新启用快速刷新功能。其他情况通常可以用类似方式解决。

错误恢复能力

语法错误

如果在开发过程中出现语法错误,您可以修复它并再次保存文件。错误将自动消失,因此您无需重新加载应用程序。您不会丢失组件状态

运行时错误

如果您的错误导致组件内部出现运行时错误,您将看到一个上下文覆盖层。修复错误后,覆盖层将自动消失,无需重新加载应用程序。

如果错误未发生在渲染期间,组件状态将被保留。如果错误发生在渲染期间,React 将使用更新后的代码重新挂载您的应用程序。

如果您的应用程序中有 错误边界(在生产环境中实现优雅降级的好方法),它们将在渲染错误后的下一次编辑时重试渲染。这意味着拥有错误边界可以防止您总是被重置到根应用状态。但请注意,错误边界不应 过于 细化。React 在生产环境中使用它们,应始终有意设计。

限制

快速刷新会尝试保留您正在编辑的组件中的本地 React 状态,但仅在安全的情况下进行。以下是您可能会看到每次编辑文件时本地状态被重置的几个原因:

  • 类组件的本地状态不会被保留(仅函数组件和 Hooks 会保留状态)。
  • 您正在编辑的文件可能 除了 React 组件外还有其他导出。
  • 有时,文件会导出调用高阶组件(如 HOC(WrappedComponent))的结果。如果返回的组件是类,其状态将被重置。
  • 匿名箭头函数如 export default () => <div />; 会导致快速刷新不保留本地组件状态。对于大型代码库,您可以使用我们的 name-default-component codemod

随着更多代码库迁移到函数组件和 Hooks,您可以预期在更多情况下状态会被保留。

提示

  • 默认情况下,快速刷新会保留函数组件(和 Hooks)中的 React 本地状态。
  • 有时您可能希望 强制 重置状态并重新挂载组件。例如,这在调整仅在挂载时发生的动画时非常有用。为此,您可以在编辑的文件中的任何位置添加 // @refresh reset。此指令仅作用于该文件,并指示快速刷新在每次编辑时重新挂载该文件中定义的组件。
  • 您可以在开发期间编辑的组件中添加 console.logdebugger;
  • 请记住,导入是区分大小写的。当您的导入与实际文件名不匹配时,快速刷新和完全刷新都可能失败。例如,'./header''./Header'

快速刷新与 Hooks

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

具有依赖项的 Hooks(如 useEffectuseMemouseCallback)在快速刷新期间 总是 会更新。它们的依赖项列表在快速刷新期间将被忽略。

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

有时,这可能导致意外结果。例如,即使 useEffect 具有空依赖项数组,在快速刷新期间仍会重新运行一次。

然而,编写能够应对 useEffect 偶尔重新运行的代码是一种良好的实践,即使没有快速刷新也是如此。这将使您更容易在以后为其引入新的依赖项,并且 React 严格模式 也强制要求这一点,我们强烈建议启用它。

On this page