Breaking changes между версиями

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


1. Структура маршрутов и маршрутизатора

В ранних версиях TanStack Router маршруты описывались преимущественно через объект RouteConfig, с возможностью указания path, component и children. Начиная с версии 2.x, структура была переработана:

  • Удаление RouteConfig в пользу декларативного описания маршрутов через Route классы.

    // Старый подход
    const routes = [
      {
        path: "/users",
        component: UsersPage,
        children: [
          { path: ":id", component: UserDetailPage }
        ]
      }
    ];
    // Новый подход
    const usersRoute = new Route({ path: "/users", component: UsersPage });
    const userDetailRoute = new Route({ path: ":id", component: UserDetailPage });
    usersRoute.addChildren([userDetailRoute]);
    const router = new Router({ routes: [usersRoute] });
  • Метод addChild заменил вложение через массив children. Теперь вложенные маршруты создаются явно через методы маршрута, что повышает читаемость и контроль над конфигурацией.

  • Свойство index теперь обязательное для индексных маршрутов. Ранее индексные маршруты определялись отсутствием path, теперь нужно явно указывать index: true.


2. Работа с хуками

В новых версиях изменился подход к хукам маршрутизации:

  • useRouteMatch был удален и заменен на useMatch, которая возвращает информацию о текущем совпадении маршрута.
  • useRouter теперь предоставляет полный объект маршрутизатора с методами navigate, preload, refresh и доступом к всем зарегистрированным маршрутам.

Пример замены:

// Старый код
const match = useRouteMatch("/users/:id");

// Новый код
const match = useMatch("/users/:id");
const router = useRouter();
  • useNavigate теперь реализуется через объект router.navigate вместо отдельного хука. Это унифицирует навигацию для всех типов компонентов.

3. Загрузка данных (loaders)

В версии 1.x TanStack Router использовал loader на уровне маршрута для асинхронной загрузки данных. В версии 2.x и выше:

  • loader заменён на loaderFn. Новое свойство принимает функцию, возвращающую Promise с данными.
  • Контекст загрузки теперь передается через аргумент функции, включая параметры маршрута, query и объект router.
// Старый синтаксис
const userLoader = async ({ params }) => {
  return fetchUser(params.id);
}

// Новый синтаксис
const userLoaderFn = async ({ params, router }) => {
  return fetchUser(params.id);
}
  • Обработка ошибок и редиректов теперь требует использования специальных методов router.navigate вместо выбрасывания исключений.

4. Навигация и работа с URL

В старых версиях маршрутизация и управление URL были более опосредованными:

  • router.push и router.replace заменены на единый метод router.navigate, принимающий объект с полями:

    • to — путь или имя маршрута,
    • replace — логическое значение для замены текущего состояния,
    • params — параметры маршрута,
    • query — query-параметры.
router.navigate({ to: "/users/1", replace: true });
  • Параметры query теперь синхронизируются с объектом маршрута через router.state.query, что требует явного чтения/записи вместо автоматического связывания.

5. Управление состоянием маршрута

Старые версии TanStack Router использовали глобальный объект состояния маршрута, который мог содержать route.state. В новых версиях:

  • route.state заменён на локальный и глобальный стейт:

    • Локальный — хранится на уровне маршрута, доступ через useLocalRouteState.
    • Глобальный — через router.state.
  • Обновление состояния стало атомарным: router.setState({ key: value }) вместо прямого присваивания.


6. Поддержка TypeScript

Breaking changes коснулись и типизации:

  • Объекты Route теперь строго типизированы. params и query должны быть объявлены через generic-параметры маршрута.
  • Ранее возможная динамическая генерация маршрутов теперь требует явного указания типов, чтобы избежать ошибок компиляции.
  • Router требует декларации всех маршрутов с их типами заранее.
const usersRoute = new Route<{ id: string }>({ path: "/users/:id", component: UserDetailPage });

7. Рекомендации по миграции

  • Проверить все loader функции и переписать их под loaderFn.
  • Заменить все хуки useRouteMatch и useNavigate на useMatch и router.navigate.
  • Явно указать index: true для индексных маршрутов.
  • Привести все маршруты к объектам класса Route и использовать addChildren вместо вложенных массивов.
  • Обновить работу с состоянием маршрутов через router.state и useLocalRouteState.
  • Привести типы параметров маршрута в соответствие с TypeScript новой версии.

Эти изменения делают TanStack Router более предсказуемым и типобезопасным, но требуют внимательной проверки существующего кода при обновлении версий.