BACK
Use casesRouter spinner — глобальная загрузка навигации
Use cases · 20

Router spinner — глобальная загрузка навигации

Паттерн

Lazy-маршруты, resolvers и guards могут грузиться секундами. Пользователю надо показать, что переход обрабатывается — глобальный spinner поверх app shell.

Какую проблему решаем

Состояние «идёт навигация» нельзя описать одним событием — Router генерирует целое семейство: NavigationStart, NavigationEnd, NavigationCancel, NavigationError. Если просто ставить флаг loading=true на Start и забыть про Cancel/Error — spinner повиснет навсегда после отмены навигации guard-ом.

Операторы и зачем они нужны

  • filter — оставляем только четыре нужных типа событий (Start + три терминальных), игнорируем шум типа RoutesRecognized.
  • map — превращаем тип события в boolean: NavigationStart → true, всё остальное → false.
  • startWith(false) — изначально приложение не грузится.
  • distinctUntilChanged — два Start подряд (при redirect) не дёргают spinner лишний раз.

Подводные камни

  • Забыть про Cancel/Error — самая частая ошибка. Spinner зависнет true навсегда после отмены guard-ом.
  • scan со счётчиком loaders нужен только для параллельных загрузок. Router navigation последовательна — счётчик избыточен.
  • Spinner в каждом page-компоненте — плохая идея. Lazy-загрузка происходит ДО создания компонента, spinner не успеет показаться. Только в app shell.

Что в итоге получаем

Один глобальный поток покрывает весь lifecycle навигации — start, успех, отмену и ошибку — без ручных флагов в компонентах.

script.ts // TypeScript
CONSOLE · Console Output
Нажмите на запуск, чтобы увидеть результат...