introduction

快速刷新是Next.js的一个特性,让你能够即刻感知到编辑React组件已经生效,快速刷新默认启动(在9.4以及更高版本),通过这个特性,大多数编辑在一秒内能够显式无需丢失组件状态 …

如何工作

  • 对于暴露的React 组件,快速刷新会更新这个文件中的代码,并且重新选择这个组件,你能够编辑这个文件的任何内容,包括样式,渲染逻辑,事件处理器或者效果 ..
  • 如果编辑的文件不是一个React 组件,那么快速刷新会重新运行这个文件,以及其他导入这个文件的文件,因此如果Button.js以及 Modal.js导入了theme.js,编辑theme.js将会同时更新组件 …
  • 最终,如果你更新的一个文件是从React 树之外的文件导入的,快速刷新将会回滚为完全重载 .. 你可能有一个文件它渲染了一个React组件,但是它也暴露了一个值,被一个非React组件导入…

这种情况下,考虑迁移约束到一个单独的文件并同时在两个文件中导入它,这样重新启动了快速刷新,其他情况通常能够以类似的方式进行解决 ….

错误恢复

语法错误

开发阶段的语法错误,你能够修复它并再次保存这个文件,这个错误将会自动的消失,因此你不需要重载app,你不会丢失组件状态 ..

运行时错误

如果由于一个错误导致组件内部运行时错误,你能够得到一个错误页面,修复这个错误将会自动的恢复正常而不会重载app ..

组件状态仍然能够得到保留,如果在渲染阶段错误没有发生,如果发生了,React将会重新挂载你的组件(通过更新的代码,这意味着组件状态将会丢失) ..

如果你存在error boundaries(在生产环境下这是一个优雅的失败提示),它将尝试重新在渲染错误的下一次编辑之后进行渲染 … 这意味着有一个错误便捷能够阻止你总是重置到根应用状态 … 但是需要记住的是错误边界不应该太细了 .. 在生产中使用它,总是应该有意的设计 ..

限制

快速刷新尝试保留局部React状态(当前编辑的组件内部的状态),但是仅当这样做是安全的,这里有一些原因可能需要了解为什么在编辑了文件之后重置了组件状态:

  • 本地状态对于类组件来说不会保留(仅仅函数式组件以及Hooks才会保留状态)
  • 你编辑的文件可能暴露了除React组件之外的其他东西 ..
  • 某些时候,一个文件可能暴露了高阶组件类似于HOC(WrappedComponent),如果它返回的组件是一个类组件,它的状态也会被重置 …
  • 匿名箭头函数,例如export default () => <div />;会导致快速刷新不会保留本地组件状态,对于大量的代码基,你能够通过使用name-default-component codemod 进行规范(也就是修改为能够进行快速刷新的形式) …

Tips

  • 默认情况下快速刷新保留函数式组件(以及 Hooks)的局部状态.
  • 某些时候你想要强制重置一个状态,让组件重新挂载,对于仅在挂载的时候补调整动画 ..

为了这样做,你能够增加 //@refresh reset到你编辑的文件的任意位置,这个指令仅对当前文件生效,并且指示快速刷新重新挂载定义在这个文件的组件(在每次编辑时) ..

  • 开发阶段,你能够放置一个console.log或者 debugger; 到组件中 ..

快速刷新以及 Hooks

特别是,快速刷新将会在编辑期间尝试保留组件的状态 … 特别是useState以及 useRef保留了它们之前的值(只要它们不改变参数或者Hook的调用顺序) …

使用了依赖的Hooks - 例如useEffect,useMemo,以及useCallback - 将总是在快速刷新期间更新 .. 它们的依赖列表将被忽略(在快速刷新发生的时候) …

举个例子,当你编辑 useMemo(() => x * 2,[x])useMemo(() => x * 10,[x]),它将重新运行,即使x`没有发生改变,如果React不这样做,那么改变不会反应到屏幕上 …

某些时候,这可能导致不期待的结果,举个例子,一个具有空数组的依赖的useEffect仍然在快速刷新中重新运行)

然而,编写代码安静的有意重新执行useEffect也是一个好的习惯(即使没有快速刷新),它将更容易在后面引入新的依赖并且对于 React Strict Mode 来说这是强制的,我们非常推荐启用这一个特性 …