Fast Refresh
Fast Refresh 是集成到 Next.js 中的 React 功能,允许你在保存文件更改时实时重载浏览器页面,同时保持临时的客户端状态。它在 9.4 或更新版本的所有 Next.js 应用程序中默认启用。启用 Fast Refresh 后,大多数编辑应该在一秒钟内可见。
工作原理
- 如果你编辑仅导出 React 组件的文件,Fast Refresh 将仅更新该文件的代码,并重新渲染你的组件。你可以编辑该文件中的任何内容,包括样式、渲染逻辑、事件处理程序或效果。
- 如果你编辑具有 不是 React 组件的导出的文件,Fast Refresh 将重新运行该文件以及导入它的其他文件。因此,如果
Button.js
和Modal.js
都导入theme.js
,编辑theme.js
将更新两个组件。 - 最后,如果你编辑一个文件,该文件被 React 树之外的文件导入,Fast Refresh 将回退到执行完全重载。你可能有一个文件渲染 React 组件,但也导出一个被非 React 组件导入的值。例如,也许你的组件也导出一个常量,而一个非 React 工具文件导入它。在这种情况下,考虑将常量迁移到单独的文件中,并将其导入到两个文件中。这将重新启用 Fast Refresh 工作。其他情况通常可以用类似的方式解决。
错误恢复
语法错误
如果你在开发过程中出现语法错误,可以修复它并再次保存文件。错误将自动消失,因此你无需重载应用程序。你不会丢失组件状态。
运行时错误
如果你犯了一个导致组件内部运行时错误的错误,你会看到一个上下文覆盖层。修复错误将自动关闭覆盖层,而无需重载应用程序。
如果错误不是在渲染期间发生的,组件状态将被保留。如果错误确实在渲染期间发生,React 将使用更新的代码重新挂载你的应用程序。
如果你的应用程序中有错误边界(这对于生产中的优雅失败是一个好主意),它们将在渲染错误后的下一次编辑时重试渲染。这意味着拥有错误边界可以防止你总是重置到根应用程序状态。但是,请记住错误边界不应该 过于 细粒度。React 在生产中使用它们,应该始终有意设计。
限制
Fast Refresh 尝试保留你正在编辑的组件中的本地 React 状态,但只有在安全的情况下才会这样做。以下是你可能看到每次编辑文件时本地状态被重置的几个原因:
- 类组件的本地状态不会被保留(只有函数组件和 Hooks 保留状态)。
- 你正在编辑的文件可能除了 React 组件之外还有 其他 导出。
- 有时,文件会导出调用高阶组件(如
HOC(WrappedComponent)
)的结果。如果返回的组件是一个类,其状态将被重置。 - 匿名箭头函数(如
export default () => <div />;
)会导致 Fast Refresh 不保留本地组件状态。对于大型代码库,你可以使用我们的name-default-component
codemod。
随着你的代码库更多地转向函数组件和 Hooks,你可以期望在更多情况下保留状态。
提示
- Fast Refresh 默认保留函数组件(和 Hooks)中的 React 本地状态。
- 有时你可能想要 强制 重置状态并重新挂载组件。例如,如果你正在调整仅在挂载时发生的动画,这可能很方便。为此,你可以在正在编辑的文件中的任何位置添加
// @refresh reset
。此指令仅对文件本地有效,并指示 Fast Refresh 在每次编辑时重新挂载在该文件中定义的组件。 - 你可以在开发过程中编辑的组件中放入
console.log
或debugger;
。 - 记住导入是区分大小写的。当你的导入与实际文件名不匹配时,快速和完全重载都可能失败。例如,
'./header'
与'./Header'
。
Fast Refresh 和 Hooks
在可能的情况下,Fast Refresh 尝试在编辑之间保留组件的状态。特别是,useState
和 useRef
会保留其先前的值,只要你没有更改它们的参数或 Hook 调用的顺序。
具有依赖项的 Hooks(如 useEffect
、useMemo
和 useCallback
)在 Fast Refresh 期间将 始终 更新。在 Fast Refresh 发生时,它们的依赖项列表将被忽略。
例如,当你将 useMemo(() => x * 2, [x])
编辑为 useMemo(() => x * 10, [x])
时,即使 x
(依赖项)没有改变,它也会重新运行。如果 React 不这样做,你的编辑就不会反映在屏幕上!
有时,这可能导致意外结果。例如,即使具有空依赖项数组的 useEffect
在 Fast Refresh 期间仍会重新运行一次。
但是,编写对 useEffect
偶尔重新运行具有弹性的代码是一个好习惯,即使没有 Fast Refresh。这将使你更容易在以后为其引入新的依赖项,并且它由React Strict Mode强制执行,我们 强烈建议启用它。