文档
架构
快速刷新
示例

快速刷新 (Fast Refresh) 是 Next.js 的一个功能,可以即时反馈你对 React 组件所做的编辑。在 9.4 或更高版本的所有 Next.js 应用中,默认启用了快速刷新。启用了 Next.js 快速刷新后,大多数编辑应该在一秒内可见,且不会丢失组件状态

工作原理

  • 如果你编辑的文件只导出 React 组件,则快速刷新只会更新该文件的代码,并重新渲染你的组件。你可以编辑该文件中的任何内容,包括样式、渲染逻辑、事件处理程序或效果。
  • 如果你编辑的文件导出的不是 React 组件,则快速刷新会重新运行该文件以及导入它的其他文件。因此,如果 Button.js 和 Modal.js 都导入了 theme.js,编辑 theme.js 将更新这两个组件。
  • 最后,如果你 编辑的文件React 树外的文件导入,则快速刷新会退回到完全重载。你可能有一个文件既渲染 React 组件,又导出一个被非 React 组件导入的常量。例如,你的组件可能还导出一个常量,一个非 React 实用程序文件导入它。在这种情况下,考虑将该常量迁移到一个单独的文件中,并在两个文件中导入它。这将重新启用快速刷新。其他情况通常也可以以类似的方式解决。

错误恢复

语法错误

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

运行时错误

如果你的组件内部出现导致运行时错误的错误,你将看到一个上下文覆盖提示。修复错误将自动关闭覆盖提示,而无需重新加载应用程序。

如果错误不是在渲染期间发生的,组件状态将会保留。如果错误确实是在渲染期间发生的,React 将使用更新后的代码重新挂载你的应用程序。

如果你的应用程序中有错误边界 (opens in a new tab)(这在生产环境中的优雅失败是个好主意),它们会在渲染错误后的下一次编辑中重新尝试渲染。这意味着错误边界可以避免你总是重置到根应用程序状态。然而,请记住错误边界不应该太细颗粒化。它们在生产环境中由 React 使用,并且应该始终有意设计。

限制

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

  • 本地状态不会为类组件保留(只有函数组件和 Hooks 保留状态)。
  • 你编辑的文件可能除了 React 组件之外还有其他导出。
  • 有时,一个文件会导出调用高阶组件的结果,如 HOC(WrappedComponent) 。如果返回的组件是类组件,其状态将被重置。
  • export default () => <div />; 这样的匿名箭头函数会导致快速刷新无法保留本地组件状态。对于大型代码库,你可以使用我们的 name-default-component 代码修改器。 随着代码库中越来越多的代码迁移到函数组件和 Hooks,你可以期待状态在更多情况下得以保留。

提示

  • 快速刷新默认会在函数组件(和 Hooks)中保留 React 本地状态。
  • 有时你可能希望强制重置状态,并重新挂载一个组件。例如,如果你正在调整只在挂载时发生的动画,这可能会很方便。为此,你可以在正在编辑的文件中的任何位置添加 // @refresh reset。这个指令是针对本地文件的,它指示快速刷新在每次编辑时重新挂载文件中定义的组件。
  • 你可以在开发期间编辑的组件中放入 console.logdebugger;

快速刷新和 Hooks

在可能的情况下,快速刷新会尝试在两次编辑之间保留组件的状态。具体而言,只要不改变的参数或 Hook 调用的顺序, useState and useRef 就会保留它们先前的值。

具有依赖关系的 Hook - 如useEffectuseMemo, 和 useCallback - 在快速刷新期间总会更新。它们的依赖关系列表在快速刷新发生时会被忽略。

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

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

但是,即使在没有快速刷新的情况下,编写能够偶尔重新运行 useEffect 的稳健代码也是个好习惯。这将使你以后更容易向其中引入新依赖项,并且这也是 React 严格模式 所强制执行的,我们强烈建议启用它。