Fallback при загрузке чанков

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


Асинхронная загрузка маршрутов

В TanStack Router маршруты могут быть определены с использованием функции loader или через динамический импорт компонентов. Например:

import { createRouter, Route } from '@tanstack/router';

const Home = React.lazy(() => import('./pages/Home'));
const About = React.lazy(() => import('./pages/About'));

const router = createRouter({
  routes: [
    {
      path: '/',
      element: <Home />,
    },
    {
      path: '/about',
      element: <About />,
    },
  ],
});

В этом примере компоненты Home и About подгружаются лениво. Пока чанк не загрузился, React не отображает компонент. Без fallback пользователь увидит пустой экран.


Использование <Suspense> для fallback

Для отображения промежуточного состояния используется стандартный механизм React — <Suspense>:

import React, { Suspense } from 'react';

function App() {
  return (
    <Suspense fallback={<div>Загрузка...</div>}>
      <RouterProvider router={router} />
    </Suspense>
  );
}

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

  • fallback принимает JSX, который будет отображен, пока загружается компонент.
  • <Suspense> может быть применен как к отдельным компонентам, так и к всему дереву маршрутов.
  • Можно использовать сложные fallback-элементы: спиннеры, анимации, прогресс-бары.

Fallback на уровне маршрута

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

const router = createRouter({
  routes: [
    {
      path: '/profile',
      element: (
        <Suspense fallback={<div>Загрузка профиля...</div>}>
          <Profile />
        </Suspense>
      ),
    },
    {
      path: '/settings',
      element: (
        <Suspense fallback={<div>Загрузка настроек...</div>}>
          <Settings />
        </Suspense>
      ),
    },
  ],
});

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


Управление fallback при ошибках загрузки

Для динамических импортов возможны ошибки, например, из-за сетевых сбоев. TanStack Router поддерживает error boundaries, которые можно комбинировать с fallback:

function ErrorFallback({ error }) {
  return <div>Произошла ошибка: {error.message}</div>;
}

const router = createRouter({
  routes: [
    {
      path: '/dashboard',
      element: (
        <ErrorBoundary FallbackComponent={ErrorFallback}>
          <Suspense fallback={<div>Загрузка панели управления...</div>}>
            <Dashboard />
          </Suspense>
        </ErrorBoundary>
      ),
    },
  ],
});

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

  • ErrorBoundary перехватывает ошибки при загрузке чанка.
  • Сочетание с <Suspense> обеспечивает плавный UX: сначала отображается fallback, затем либо компонент, либо сообщение об ошибке.
  • Можно создавать отдельные error boundaries для каждого маршрута для более точной обработки.

Прогрессивная загрузка чанков

TanStack Router поддерживает стратегию prefetch и progressive loading, что улучшает UX:

import { Link } from '@tanstack/router';

function Navigation() {
  return (
    <>
      <Link to="/profile" preload="intent">Профиль</Link>
      <Link to="/settings" preload="intent">Настройки</Link>
    </>
  );
}
  • Атрибут preload="intent" инициирует предварительную загрузку чанка при наведении курсора.
  • Это снижает время ожидания fallback при переходе на страницу.
  • Можно комбинировать с <Suspense> для плавной анимации прогресса загрузки.

Динамический fallback на основе состояния

Иногда требуется отображать fallback, зависящий от состояния загрузки данных:

function ProfileLoader() {
  const { data, isLoading } = useProfileData();

  if (isLoading) {
    return <div>Загрузка данных профиля...</div>;
  }

  return <Profile data={data} />;
}
  • Использование состояния загрузки позволяет показывать прогресс не только при загрузке чанка, но и при получении данных.
  • Это комбинируется с <Suspense> для полной поддержки асинхронного контента на странице.

Рекомендации по организации fallback

  1. Минимизировать блокирующий контент — отображать только необходимые индикаторы загрузки.
  2. Использовать локальные fallback для крупных страниц с тяжелыми компонентами.
  3. Комбинировать <Suspense> с Error Boundaries для надежного UX.
  4. Рассмотреть предзагрузку чанков для часто посещаемых страниц.
  5. Использовать динамический текст fallback для отражения состояния загрузки данных или компонентов.

Эта система позволяет создавать плавное взаимодействие с пользователем даже в сложных приложениях с большим количеством лениво загружаемых компонентов, обеспечивая управляемые fallback-элементы и обработку ошибок на уровне маршрутов.