Глобальные индикаторы загрузки

Глобальные индикаторы загрузки позволяют визуально сигнализировать пользователю о том, что выполняется асинхронная операция или происходит навигация между маршрутами. В TanStack Router это реализуется через встроенные механизмы отслеживания состояния маршрутов и их загрузок, что делает управление состоянием загрузки максимально декларативным и гибким.

Отслеживание состояния маршрута

Каждый маршрут в TanStack Router может иметь асинхронные загрузочные функции, такие как loader или action. Эти функции возвращают промисы, выполнение которых можно отслеживать для отображения индикаторов загрузки. Ключевой элемент — свойство pending маршрута. Оно отражает, выполняется ли в данный момент асинхронная операция:

import { useRouter, RouterProvider } from '@tanstack/router'

function App() {
  const router = useRouter()

  return (
    <>
      {router.isPending && <div className="global-loader">Загрузка...</div>}
      <RouterProvider router={router} />
    </>
  )
}

Пояснение:

  • router.isPending автоматически отслеживает все активные асинхронные операции на маршрутах.
  • Индикатор отображается до завершения всех загрузок, после чего исчезает.

Использование pending на уровне маршрутов

Помимо глобального состояния, TanStack Router позволяет отслеживать загрузку конкретного маршрута через useMatch:

import { useMatch } from '@tanstack/router'

function RouteComponent() {
  const match = useMatch('/profile')

  return (
    <>
      {match.pending ? <Spinner /> : <Profile />}
    </>
  )
}

Особенности:

  • match.pending активен только для данного маршрута.
  • Позволяет комбинировать глобальный и локальный индикатор загрузки для разных уровней интерфейса.

Интеграция с асинхронными данными

TanStack Router поддерживает загрузку данных через loader функции, которые возвращают промисы:

const profileRoute = {
  path: '/profile',
  loader: async () => {
    const response = await fetch('/api/profile')
    if (!response.ok) throw new Error('Ошибка загрузки')
    return response.json()
  }
}

Состояние pending автоматически учитывает выполнение этих промисов. Для более детального контроля можно использовать router.transition:

const router = useRouter()

useEffect(() => {
  const unsub = router.transition.subscribe(transition => {
    if (transition.status === 'pending') setLoading(true)
    else setLoading(false)
  })
  return unsub
}, [router])

Ключевые моменты:

  • Подписка на router.transition позволяет отслеживать любую навигацию и асинхронные операции.
  • Можно создавать собственные индикаторы с анимацией или прогресс-барами.

Совместное использование с Suspense

TanStack Router интегрируется с React Suspense, что позволяет декларативно показывать индикаторы загрузки при рендеринге асинхронных данных:

import { Suspense } from 'react'

<Suspense fallback={<div>Загрузка данных...</div>}>
  <Profile />
</Suspense>

Преимущества:

  • Позволяет комбинировать глобальные и локальные индикаторы.
  • Автоматическая интеграция с loader и компонентами, использующими React.lazy.

Визуальное оформление глобального индикатора

Для UX рекомендуется отображать глобальный индикатор только при длительных загрузках, чтобы не создавать мерцание интерфейса. Типичные подходы:

  • Использование задержки перед показом индикатора:
const [showLoader, setShowLoader] = useState(false)

useEffect(() => {
  if (router.isPending) {
    const timer = setTimeout(() => setShowLoader(true), 200)
    return () => clearTimeout(timer)
  } else {
    setShowLoader(false)
  }
}, [router.isPending])
  • Анимация прогресса с постепенным заполнением:
.global-loader {
  height: 4px;
  width: 0%;
  background-color: #007aff;
  transition: width 0.3s ease;
}

.global-loader.active {
  width: 100%;
}

Комбинирование с несколькими маршрутами

В крупных приложениях может быть несколько одновременно активных маршрутов. TanStack Router учитывает состояние всех асинхронных операций и объединяет их в единый isPending флаг. Это позволяет:

  • Отображать один глобальный индикатор для всех операций.
  • Сохранять локальные индикаторы для конкретных разделов страницы.

Глобальные индикаторы загрузки в TanStack Router обеспечивают простое, но мощное управление асинхронными состояниями приложения. Использование isPending, match.pending, подписок на transition и интеграция с Suspense позволяет строить интерфейсы с плавной навигацией и визуальной обратной связью для пользователя.