跳到内容

快速刷新

快速刷新是集成到 Next.js 中的 React 特性,它允许您在保存文件更改时实时重新加载浏览器页面,同时保持临时的客户端状态。它在所有 9.4 或更高版本的 Next.js 应用程序中默认启用。启用快速刷新后,大多数编辑应该在一秒钟内可见。

工作原理

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

错误恢复

语法错误

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

运行时错误

如果您在组件中犯了一个导致运行时错误的错误,您会看到一个上下文叠加层。修复错误将自动关闭叠加层,而无需重新加载应用程序。

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

如果您的应用程序中有错误边界(这对于生产环境中优雅地处理故障是一个好主意),它们将在渲染错误发生后的下一次编辑时重试渲染。这意味着拥有错误边界可以防止您总是被重置到根应用程序状态。但是,请记住错误边界不应该过于精细。它们由 React 在生产环境中使用,并且应该始终经过精心设计。

限制

快速刷新尝试保留您正在编辑的组件中的局部 React 状态,但只有在安全的情况下才会这样做。以下是一些每次编辑文件时局部状态可能被重置的原因:

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

随着您的代码库更多地转向函数组件和 Hooks,您可以期待在更多情况下状态得到保留。

提示

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

快速刷新与 Hook

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

带有依赖项的 Hooks(例如 `useEffect`、`useMemo` 和 `useCallback`)将在快速刷新期间**总是**更新。它们的依赖项列表在快速刷新发生时将被忽略。

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

有时,这可能导致意想不到的结果。例如,即使是带有空依赖项数组的 `useEffect` 也会在快速刷新期间重新运行一次。

然而,编写对 `useEffect` 偶尔重新运行具有弹性的代码,即使没有快速刷新,也是一种好习惯。它将使您以后更容易引入新的依赖项,并且它由 React 严格模式强制执行,我们强烈建议您启用它。