• react
  • lazy
  • suspense

Используйте React.lazy уверенно: Безопасный способ загружать компоненты при быстрой итерации

React.lazy — это отличный способ загружать компоненты по запросу и улучшать производительность вашего приложения. Однако иногда это может привести к проблемам, таким как "ChunkLoadError" и "Loading chunk failed".

Gao
Gao
Founder

Дилемма

Сегодня разработка программного обеспечения движется быстрее под популярной философией "двигайся быстро и ломай всё". Без осуждения — это просто так устроено. Однако такой высокий темп может иногда приводить к проблемам, особенно когда дело касается загрузки компонентов в React.

Если ты работаешь над проектом, который использует React.lazy для загрузки компонентов по требованию, ты мог столкнуться с такими проблемами, как ChunkLoadError и Loading chunk failed. Вот некоторые возможные причины:

  • Проблема с сетью, например, соединение пользователя с интернетом медленное или нестабильное.
  • Пользователь использует устаревшую версию приложения, и браузер пытается загрузить фрагмент, который больше не существует.

Обычно простое обновление страницы может решить проблему, но это не лучшая пользовательская ситуация. Представь, что при переходе на другой маршрут у пользователя появляется белый экран — это не придаёт твоему приложению привлекательности.

Можем ли мы сбалансировать необходимость в скорости и плавный пользовательский опыт? Конечно. Я покажу тебе, как это сделать (с использованием TypeScript, разумеется).

Решение

Брутальным решением может быть сохранение всех версий фрагментов на сервере, чтобы избежать проблемы с "недостающим фрагментом". Однако по мере роста приложения такое решение может стать непрактичным из-за увеличения требований к дисковому пространству, и оно всё равно не решает проблему сети.

Учитывая, что повторные попытки или обновление могут решить проблему, мы можем реализовать эти решения в коде. Поскольку проблема обычно возникает, когда пользователь переходит на другой маршрут, мы можем решить её, даже не заметив пользователя. Всё, что нам нужно, это создать обёртку вокруг функции React.lazy, которая будет обрабатывать повторные попытки и обновления.

Уже существует несколько отличных статей о том, как реализовать такое решение, так что я сосредоточусь на идее и внутренней работе решения.

Создание обёртки

Первый шаг — создать обёртку вокруг функции React.lazy:

Обработка повторных попыток

Для проблем с сетью мы можем обрабатывать повторные попытки, оборачивая importFunction в функцию tryImport:

Выглядит просто, да? Ты также можешь реализовать экспоненциальный откат, чтобы более эффективно обрабатывать повторные попытки.

Обработка обновлений

Для проблемы с устаревшей версией можно обрабатывать обновления путём отлова ошибки и обновления страницы:

Однако такая реализация очень опасна, так как может вызвать бесконечный цикл обновлений, если ошибка не может быть решена обновлением. Между тем, состояние приложения будет потеряно при обновлении. Поэтому нам нужна помощь sessionStorage, чтобы сохранить сообщение о том, что мы уже пытались обновить страницу:

Теперь, когда мы ловим ошибку из функции safeLazy, мы знаем, что это что-то, что не может быть решено обновлением.

Несколько ленивых компонентов на одной странице

В текущей реализации есть ещё одна скрытая опасность. Если у тебя на странице несколько ленивых компонентов, бесконечный цикл обновлений всё равно может возникнуть из-за того, что другие компоненты могут сбросить значение sessionStorage. Чтобы решить эту проблему, мы можем использовать уникальный ключ для каждого компонента:

Теперь у каждого компонента будет свой собственный ключ sessionStorage, и цикл бесконечных обновлений будет предотвращён. Мы можем продолжать дорабатывать решение, например:

  • Соберём все ключи в массив, чтобы использовать только один ключ хранения.
  • Установим лимит обновлений, чтобы обновлять страницу больше одного раза перед выбросом ошибки.

Но я думаю, ты уловил суть. Всеобъемлющее решение на TypeScript с тестами и конфигурациями доступно в GitHub репозитории. Я также опубликовал пакет react-safe-lazy на NPM, чтобы ты мог сразу использовать его в своём проекте.

Заключение

Разработка программного обеспечения — это тонкая работа, и даже самые мелкие детали могут потребовать усилий для решения. Я надеюсь, что эта статья поможет тебе изящно справиться с проблемами React.lazy и улучшить пользовательский опыт твоего приложения.