React Fast Refresh стал важным шагом для нормального developer experience в React-проектах. До него hot reloading часто работал «почти хорошо», но ломался на сложных случаях, путал состояние и создавал лишнее недоверие к инструменту.

React Fast Refresh является преемником React Hot Loader. Он полностью поддерживается командой React и первоначально был выпущен вместе с React Native 0.6.1 в 2019 году.

Если читать этот пост сегодня, основной интерес здесь не в старых переключателях для CRA, а в самом сдвиге: React-инструменты стали меньше полагаться на хрупкие хаки вокруг hot reload и больше - на официально поддерживаемую интеграцию с экосистемой.

Почему же React Fast Refresh

Причина в том, что React Hot Loader не был совершенен, поэтому опыт разработки тоже не был отличным. Вот документация по устранению неполадок.

Вот заявление, которое можно найти в репозитории React Hot Loader, которое суммирует это и подготавливает почву для быстрого обновления:

React-Hot-Loader has been your friendly neighbour, living outside of React. But it has been limiting its powers and causing not the greatest experience. It’s time to make a next step.

React Fast Refresh призван решить все эти проблемы и обеспечить гораздо лучший опыт разработки с надежной Hot Module Replacement за счёт сохранения точного состояния компонентов между перезагрузками с использованием более интеллектуального API.

Из чего он состоит

React Fast Refresh опирается на сочетание следующих технологий:

  • React Renderer 16.9.0+;
  • react-refresh/runtime;
  • react-refresh/babel babel плагин;
  • Hot module replacement включена в бандлере (Webpack и т. д.).

Это означает, что он не может работать с предыдущими версиями React, такими как React 15, например.

Как это работает

Некоторые ключевые моменты:

  • он будет повторно рендерить компонент React, когда мы редактируем модуль, который экспортирует только компоненты React;
  • перезагрузит все компоненты React, которые импортируют не-React модуль и сам модуль, когда мы его редактируем;
  • выполнит полную перезагрузку, когда мы редактируем модуль вне дерева React;
  • продолжит работать, как только мы исправим синтаксис или ошибку во время выполнения без перезагрузки вручную;
  • для function components и Hooks будет сохранено локальное состояние;
  • локальное состояние не будет сохранено для class components.

Если есть желание - можешь прочесть подробное объяснение в React Native docs.

Create React App

В настоящее время CRA использует Webpack API Hot Module Replacement для применения быстрых обновлений и полной перезагрузки страницы, когда это невозможно. При внимательном осмотре react-dev-utils можно увидеть, как весь этот механизм работает под капотом.

CRA скоро будет поддерживать React Fast Refresh в качестве экспериментальной функции. Единственное, что нам нужно сделать, это явно установить переменную окружения с именем FAST_REFRESH в файле .env:

FAST_REFRESH=true

На самом деле всё, что осталось до его официального включения в будущие выпуски CRA, - это решить некоторые проблемы, которые до сих пор остаются в пакете Webpack.

Под капотом используется плагин @pmmmwh/react-refresh-webpack-plugin. Так что React Fast Refresh может работать, но определенно есть то, что нужно сделать, как упомянуто в репозитории:

First - this plugin is not 100% stable. It works pretty reliably, and we have been testing it for some time, but there are still edge cases yet to be discovered. Please DO NOT use it if you cannot afford to face breaking changes in the future.

Вот почему Fast Refresh будет считаться экспериментальной функцией в течение следующих месяцев и будет включена в CRA с использованием FAST_REFRESH.

Исторический контекст интеграции

На момент написания этой статьи некоторые изменения, касающиеся Fast Refresh, уже были внесены в документы CRA в основной ветке.

Подробное техническое описание о Fast Refresh можно найти здесь.

Ты можешь использовать Fast Refresh сегодня с использованием customize-cra. Подробнее здесь

Next.js уже поддерживает его как экспериментальную функцию в версии v9.3.6, если мы включим его в next.config.js.

Итог

Смысл Fast Refresh не в самой перезагрузке, а в том, чтобы итерация между правкой и проверкой кода стала короче и надежнее. Для React-разработки это один из тех DX-инструментов, которые быстро перестаешь замечать, но очень скучаешь, когда их нет.

Полезный вывод отсюда сегодня такой: если hot reload в проекте нестабилен, это проблема не только удобства, но и доверия к инструментам. Чем меньше “магии” и нестандартных интеграций вокруг него, тем спокойнее ежедневная разработка.