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

Примеры

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

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

Советы

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

Fast Refresh и хуки

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

Хуки с зависимостями — такие как useEffect, useMemo и useCallbackвсегда обновляются во время Fast Refresh. Их список зависимостей игнорируется во время быстрого обновления.

Например, при изменении useMemo(() => x * 2, [x]) на useMemo(() => x * 10, [x]) хук перезапустится, даже если x (зависимость) не изменился. Если бы React этого не делал, ваши правки не отразились бы на экране!

Иногда это может привести к неожиданным результатам. Например, даже useEffect с пустым массивом зависимостей выполнится один раз во время Fast Refresh.

Однако написание кода, устойчивого к случайному повторному выполнению useEffect, является хорошей практикой даже без Fast Refresh. Это упростит добавление новых зависимостей в будущем и соответствует требованиям React Strict Mode, который мы настоятельно рекомендуем включать.