Миграция с React Router

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


Конфигурация маршрутов

В React Router маршруты обычно определяются через JSX-компоненты и . В TanStack Router используется декларативная конфигурация через объекты маршрутов:

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

const rootRoute = {
  path: '/',
  component: RootLayout,
  children: [
    {
      path: 'dashboard',
      component: Dashboard,
    },
    {
      path: 'profile/:userId',
      component: Profile,
    },
  ],
};

const router = createReactRouter({
  routeTree: rootRoute,
});

Ключевые отличия:

  • Все маршруты строятся в виде дерева объектов, а не JSX.
  • Параметры маршрутов (:userId) доступны через хук useParams или напрямую в объекте routeContext.

Работа с параметрами и динамическими маршрутами

В React Router динамические сегменты получали через useParams():

const { userId } = useParams();

В TanStack Router можно использовать аналогично, но с типизацией:

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

const Profile = () => {
  const { userId } = useParams();
  return 
Профиль пользователя {userId}
; };

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

const profileRoute = {
  path: 'profile/:userId',
  component: Profile,
  loader: async ({ params }) => {
    const response = await fetch(`/api/users/${params.userId}`);
    return response.json();
  },
};

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

Одно из главных преимуществ TanStack Router — интеграция с загрузкой данных на уровне маршрутов.

Пример использования loader:

const dashboardRoute = {
  path: 'dashboard',
  component: Dashboard,
  loader: async () => {
    const response = await fetch('/api/dashboard');
    return response.json();
  },
};

В компоненте данные можно получить через хук useLoaderData:

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

const Dashboard = () => {
  const data = useLoaderData();
  return 
{JSON.stringify(data)}
; };

Преимущества подхода:

  • Данные подгружаются до рендера компонента.
  • Упрощается управление состоянием загрузки и ошибок.

Навигация и ссылки

В React Router навигация осуществляется через или useNavigate(). В TanStack Router подход схож, но с расширением типов маршрутов:

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

На дашборд

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

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

  • router.navigate поддерживает полное описание параметров и query.
  • Типизированные маршруты предотвращают ошибки передачи параметров.

Обработка ошибок и fallback-компоненты

TanStack Router позволяет определять errorElement на уровне маршрута:

const profileRoute = {
  path: 'profile/:userId',
  component: Profile,
  loader: async ({ params }) => {
    const res = await fetch(`/api/users/${params.userId}`);
    if (!res.ok) throw new Error('Пользователь не найден');
    return res.json();
  },
  errorElement: ProfileError,
};

Это позволяет локализовать обработку ошибок по конкретным маршрутам без глобальных обработчиков.


Редиректы

Редиректы в React Router через заменяются в TanStack Router методом router.navigate с указанием опции replace:

router.navigate({ to: '/login', replace: true });

Также можно задать редиректы прямо в конфигурации маршрутов через loader или beforeLoad:

const dashboardRoute = {
  path: 'dashboard',
  loader: async ({ context }) => {
    if (!context.user) {
      return { redirectTo: '/login' };
    }
  },
};

Поддержка вложенных маршрутов и layout-компонентов

TanStack Router упрощает создание вложенных структур:

const appRoute = {
  path: '/',
  component: AppLayout,
  children: [
    { path: 'dashboard', component: Dashboard },
    { path: 'profile/:userId', component: Profile },
  ],
};

Разница с React Router:

  • Layout-компоненты напрямую встроены в дерево маршрутов.
  • Loader и errorElement могут наследоваться от родительского маршрута.

Интеграция с query и состоянием приложения

TanStack Router позволяет связывать маршруты с асинхронными запросами через loader, что упрощает управление состоянием и синхронизацию URL с данными:

const searchRoute = {
  path: 'search',
  loader: async ({ search }) => {
    const response = await fetch(`/api/search?q=${search.q}`);
    return response.json();
  },
};

Использование параметров query происходит через объект search в loader или useSearchParams в компоненте.