Быстрое обновление (Fast Refresh)

Быстрое обновление (Fast Refresh) — это функция React, интегрированная в Next.js, которая позволяет перезагружать страницу в браузере в реальном времени, сохраняя временное состояние на стороне клиента при сохранении изменений в файле. Она включена по умолчанию во всех приложениях Next.js начиная с версии 9.4 и новее. При включённом 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 перемонтирует ваше приложение с использованием обновлённого кода.

Если в вашем приложении есть границы ошибок (error boundaries) (что является хорошей практикой для корректной обработки ошибок в продакшене), они попытаются выполнить рендеринг снова после следующего изменения кода. Это означает, что границы ошибок могут предотвратить сброс состояния к корневому состоянию приложения. Однако помните, что границы ошибок не должны быть слишком детализированными. Они используются React в продакшене и должны быть тщательно продуманы.

Ограничения

Fast Refresh пытается сохранить локальное состояние React в редактируемом компоненте, но только если это безопасно. Вот несколько причин, по которым локальное состояние может сбрасываться при каждом изменении файла:

  • Локальное состояние не сохраняется для классовых компонентов (только функциональные компоненты и хуки сохраняют состояние).
  • Файл, который вы редактируете, может содержать другие экспорты помимо React-компонента.
  • Иногда файл может экспортировать результат вызова компонента высшего порядка, например HOC(WrappedComponent). Если возвращаемый компонент является классом, его состояние будет сброшено.
  • Анонимные стрелочные функции, такие как export default () => <div />;, приводят к тому, что Fast Refresh не сохраняет локальное состояние компонента. Для больших кодовых баз можно использовать наш codemod name-default-component.

По мере перехода вашей кодовой базы на функциональные компоненты и хуки, состояние будет сохраняться в большем количестве случаев.

Советы

  • Fast Refresh по умолчанию сохраняет локальное состояние React в функциональных компонентах (и хуках).
  • Иногда может потребоваться принудительно сбросить состояние и перемонтировать компонент. Например, это полезно при настройке анимации, которая происходит только при монтировании. Для этого можно добавить // @refresh reset в любое место редактируемого файла. Эта директива действует только в пределах файла и указывает Fast Refresh перемонтировать компоненты, определённые в этом файле, при каждом изменении.
  • Вы можете добавлять console.log или debugger; в компоненты, которые редактируете во время разработки.
  • Помните, что импорты чувствительны к регистру. Как быстрое, так и полное обновление могут не сработать, если импорт не соответствует фактическому имени файла. Например, './header' vs './Header'.

Fast Refresh и хуки

По возможности Fast Refresh пытается сохранить состояние компонента между изменениями. В частности, useState и useRef сохраняют свои предыдущие значения, пока вы не измените их аргументы или порядок вызова хуков.

Хуки с зависимостями, такие как 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, который мы настоятельно рекомендуем включать.