Программное определение маршрутов

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


Создание маршрутов

Маршруты создаются с помощью функции createRouter, которая принимает конфигурацию маршрутов в виде массива объектов. Каждый объект описывает путь, компонент, асинхронные данные и дочерние маршруты.

import { createRouter, RouterProvider } from '@tanstack/router';
import HomePage from './pages/HomePage';
import ProfilePage from './pages/ProfilePage';

const router = createRouter({
  routes: [
    {
      path: '/',
      component: HomePage,
    },
    {
      path: '/profile/:userId',
      component: ProfilePage,
    },
  ],
});

<RouterProvider router={router} />;

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

  • path — строка пути маршрута, поддерживает динамические сегменты через двоеточие (:userId).
  • component — компонент, который рендерится при совпадении маршрута.
  • Возможность вложенности через children.

Динамические маршруты

TanStack Router поддерживает динамические сегменты маршрута и предоставляет API для извлечения параметров:

const ProfilePage = ({ params }) => {
  return <div>Профиль пользователя: {params.userId}</div>;
};
  • params автоматически содержит значения динамических сегментов пути.
  • Позволяет строить маршруты вида /posts/:postId/comments/:commentId.

Вложенные маршруты

Для создания иерархий страниц используется ключ children:

const router = createRouter({
  routes: [
    {
      path: '/dashboard',
      component: DashboardLayout,
      children: [
        {
          path: 'analytics',
          component: AnalyticsPage,
        },
        {
          path: 'settings',
          component: SettingsPage,
        },
      ],
    },
  ],
});

Особенности вложенных маршрутов:

  • Вложенные маршруты автоматически наследуют путь родителя.
  • Родительский компонент может рендерить дочерние через <Outlet />.
  • Поддерживается ленивое подключение дочерних маршрутов.

Асинхронная загрузка данных

Маршруты могут содержать loader-функции, которые выполняются перед рендерингом компонента:

const router = createRouter({
  routes: [
    {
      path: '/posts/:postId',
      component: PostPage,
      loader: async ({ params }) => {
        const response = await fetch(`/api/posts/${params.postId}`);
        return response.json();
      },
    },
  ],
});
  • loader получает объект с params, query, context.
  • Результат loader передаётся в компонент через пропсы.
  • Позволяет избегать состояния загрузки внутри компонентов.

Обработка ошибок маршрутов

Каждый маршрут может иметь собственный ErrorBoundary:

{
  path: '/profile/:userId',
  component: ProfilePage,
  errorComponent: ProfileErrorBoundary,
}
  • При возникновении ошибки в loader или компоненте рендерится errorComponent.
  • Обеспечивает локализованную обработку ошибок на уровне маршрута.

Программная навигация

TanStack Router поддерживает навигацию через API маршрутизатора:

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

const navigateToProfile = () => {
  const router = useRouter();
  router.navigate({ to: '/profile/123' });
};

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

  • navigate позволяет указать путь и опционально состояние или query-параметры.
  • Поддерживает программное перенаправление внутри loader или action.

Программная генерация маршрутов

Можно создавать маршруты динамически, используя функции и массивы данных:

const users = [{ id: 1 }, { id: 2 }];

const userRoutes = users.map(user => ({
  path: `/users/${user.id}`,
  component: UserPage,
}));

const router = createRouter({
  routes: [
    { path: '/', component: HomePage },
    ...userRoutes,
  ],
});
  • Позволяет генерировать маршруты на основе конфигураций, API или данных.
  • Удобно для больших приложений с большим количеством динамических страниц.

Lazy-роутинг и разделение кода

Для оптимизации производительности можно загружать компоненты маршрутов лениво:

import { lazy } from 'react';

const DashboardPage = lazy(() => import('./pages/DashboardPage'));

{
  path: '/dashboard',
  component: DashboardPage,
}
  • Поддерживает интеграцию с React.Suspense.
  • Уменьшает размер начальной загрузки приложения.
  • Позволяет управлять загрузкой по мере необходимости.

Контекст и состояния маршрутов

Маршруты могут использовать context для передачи данных в дочерние компоненты:

const router = createRouter({
  routes: [
    {
      path: '/app',
      component: AppLayout,
      context: { theme: 'dark' },
      children: [
        { path: 'home', component: HomePage },
      ],
    },
  ],
});
  • Дочерние маршруты получают доступ к контексту родителя.
  • Позволяет создавать глобальные или локальные состояния маршрутов.

Поддержка TypeScript

TanStack Router полностью типизирован:

type RouterParams = {
  userId: string;
};

const router = createRouter<RouterParams>({
  routes: [
    {
      path: '/profile/:userId',
      component: ProfilePage,
    },
  ],
});
  • Параметры маршрутов типизируются для безопасной навигации.
  • Снижается риск ошибок при передаче параметров или данных loader.

Ключевые преимущества программного определения маршрутов

  1. Иерархичность и вложенность — маршруты строятся как дерево, что упрощает организацию приложения.
  2. Динамичность — маршруты можно генерировать программно на лету.
  3. Асинхронность — загрузка данных до рендеринга.
  4. Локальная обработка ошибок — отдельные ErrorBoundary на каждом маршруте.
  5. Типизация и безопасность — полностью совместимо с TypeScript, предотвращает ошибки параметров.
  6. Ленивая загрузка компонентов — уменьшение времени первой загрузки.

Если требуется, я могу подготовить отдельную секцию с практическими шаблонами программного определения маршрутов для типичных приложений, включая dashboard, e-commerce и блоги, чтобы показать реальное применение всех перечисленных функций. Это будет как раз следующий уровень глубины.