Приоритеты и порядок разрешения маршрутов

В TanStack Router маршруты определяются с использованием объектов, которые включают путь (path), компонент (component) и дочерние маршруты (children). Структура маршрутов формирует дерево, и порядок разрешения маршрутов напрямую зависит от этого дерева, а также от приоритетов, присвоенных маршрутам.

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


Специфичность маршрута

Специфичность — это мера «точности» маршрута по сравнению с URL. TanStack Router присваивает более высокий приоритет маршрутам с:

  • фиксированными сегментами (/users/settings)
  • меньшим количеством динамических сегментов (:id)
  • отсутствием wildcard-паттернов (*)

Пример:

const routes = [
  { path: "/users/:id", component: User },
  { path: "/users/settings", component: UserSettings }
];

При переходе на /users/settings TanStack Router выберет маршрут /users/settings, а не /users/:id, несмотря на то, что оба маршрута могут соответствовать URL.


Порядок обработки вложенных маршрутов

TanStack Router поддерживает вложенные маршруты через свойство children. Разрешение происходит рекурсивно:

  1. Родительский маршрут проверяется на совпадение с текущим URL.
  2. Если совпадение найдено, выполняется проверка дочерних маршрутов.
  3. Если дочерний маршрут подходит лучше по специфичности, он становится активным.

Пример структуры:

const routes = [
  {
    path: "/dashboard",
    component: DashboardLayout,
    children: [
      { path: "analytics", component: AnalyticsPage },
      { path: "reports", component: ReportsPage }
    ]
  }
];

При переходе на /dashboard/analytics сначала совпадет /dashboard, а затем проверяется дочерний маршрут analytics.


Wildcard и динамические сегменты

Динамические сегменты (:param) имеют среднюю специфичность. Они работают как переменные, но уступают фиксированным сегментам.

Wildcard (*) используется для маршрутов, которые должны совпадать с любым подмаршрутом. Wildcard всегда имеет низкий приоритет, поэтому его следует размещать после всех конкретных маршрутов.

Пример:

const routes = [
  { path: "/files/:fileId", component: FilePage },
  { path: "/files/*", component: FileFallback }
];

Переход на /files/123 выберет FilePage, а переход на /files/unknown/pathFileFallback.


Приоритеты при конфликте маршрутов

В случае одинаковой специфичности TanStack Router ориентируется на порядок объявления маршрутов в массиве. Первый объявленный маршрут получает более высокий приоритет.

Пример:

const routes = [
  { path: "/products/:id", component: ProductPage },
  { path: "/products/:name", component: ProductByName }
];

Переход на /products/42 выберет ProductPage, так как он объявлен первым.

Важно: избегать неоднозначных маршрутов, где динамические сегменты могут перекрывать друг друга, иначе разрешение маршрута становится непредсказуемым.


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

Для более сложных сценариев используются nested wildcards, которые позволяют обрабатывать произвольные URL на уровне дочерних маршрутов. Они полезны для страниц с неизвестной глубиной навигации, например, для документации или файловой структуры.

Пример:

const routes = [
  {
    path: "/docs",
    component: DocsLayout,
    children: [
      { path: "*", component: DocsCatchAll }
    ]
  }
];

Любой путь, начинающийся с /docs, будет сопоставлен с дочерним wildcard маршрутом, но если существуют более конкретные дочерние маршруты, они будут проверяться первыми.


Практические рекомендации

  • Всегда располагать конкретные маршруты выше wildcard и динамических.
  • Для вложенных маршрутов строить дерево, отражающее иерархию UI.
  • Избегать маршрутов с одинаковой спецификой, чтобы исключить неопределённое поведение.
  • Использовать index маршруты для определения стандартной страницы по умолчанию в родительском маршруте.