Относительные пути во вложенных роутах

В библиотеке Universal Router маршрутизация строится на основе дерева маршрутов, где каждый маршрут может иметь дочерние маршруты. Работа с относительными путями во вложенных роутерах позволяет создавать компактные, модульные маршруты и управлять навигацией без дублирования базовых частей URL.

Структура вложенных маршрутов

Вложенные маршруты задаются через свойство children объекта маршрута. Каждый дочерний маршрут наследует контекст родителя, что упрощает построение URL и логику обработки. Пример структуры:

import UniversalRouter from 'universal-router';

const routes = [
  {
    path: '/dashboard',
    action: () => 'Главная панель',
    children: [
      {
        path: 'analytics',
        action: () => 'Аналитика'
      },
      {
        path: 'settings',
        action: () => 'Настройки'
      }
    ]
  }
];

const router = new UniversalRouter(routes);

Здесь маршруты analytics и settings являются относительными, их полный путь формируется автоматически: /dashboard/analytics и /dashboard/settings.

Принцип работы относительных путей

Относительные пути не начинаются с символа /. Если указать путь с ведущим /, Universal Router интерпретирует его как абсолютный, игнорируя родительский маршрут.

Пример различия:

// Абсолютный путь
{ path: '/settings', action: () => 'Настройки' }

// Относительный путь
{ path: 'settings', action: () => 'Настройки' }
  • Абсолютный путь всегда начинает поиск с корня маршрутов.
  • Относительный путь комбинируется с путем родителя.

Динамические сегменты во вложенных маршрутах

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

const routes = [
  {
    path: '/users',
    children: [
      {
        path: ':id',
        action: ({ params }) => `Пользователь ${params.id}`,
        children: [
          {
            path: 'profile',
            action: ({ params }) => `Профиль пользователя ${params.id}`
          },
          {
            path: 'settings',
            action: ({ params }) => `Настройки пользователя ${params.id}`
          }
        ]
      }
    ]
  }
];

Запрос /users/42/profile вернет строку "Профиль пользователя 42", а /users/42/settings"Настройки пользователя 42". Параметры автоматически наследуются вложенными маршрутами.

Родительский контекст и относительные пути

Дочерний маршрут получает контекст родителя, включая параметры и дополнительные свойства, переданные через объект context. Это позволяет создавать маршруты, которые используют общие данные без повторного определения.

const routes = [
  {
    path: '/projects',
    action: (context) => `Проекты пользователя ${context.user}`,
    children: [
      {
        path: ':projectId',
        action: (context, params) => `Проект ${params.projectId} пользователя ${context.user}`
      }
    ]
  }
];

const router = new UniversalRouter(routes);
router.resolve('/projects/123', { user: 'Alice' }).then(console.log);
// Результат: "Проект 123 пользователя Alice"

Контекст можно расширять на любом уровне, сохраняя относительные маршруты независимыми от внешнего кода.

Применение children и относительных путей

Важное преимущество использования children заключается в том, что можно создавать группы маршрутов, которые логически связаны, без дублирования базового пути. Пример модульной структуры:

const adminRoutes = [
  {
    path: '/admin',
    children: [
      { path: 'users', action: () => 'Управление пользователями' },
      { path: 'roles', action: () => 'Управление ролями' }
    ]
  }
];

const appRoutes = [
  { path: '/', action: () => 'Главная' },
  ...adminRoutes
];

const router = new UniversalRouter(appRoutes);
  • /admin/users и /admin/roles формируются автоматически.
  • Логика вложенных маршрутов изолирована и может переиспользоваться.

Особенности навигации с относительными путями

  • Относительный путь всегда интерпретируется относительно ближайшего родителя с определённым path.
  • Если родитель не имеет path, относительный маршрут считается относительно корня.
  • При разрешении маршрута Universal Router проходит по дереву, на каждом уровне проверяя соответствие сегментов.

Использование с асинхронными действиями

Относительные маршруты поддерживают асинхронные action функции:

const routes = [
  {
    path: '/products',
    children: [
      {
        path: ':id',
        async action({ params }) {
          const product = await fetch(`/api/products/${params.id}`).then(res => res.json());
          return product.name;
        }
      }
    ]
  }
];

Асинхронность интегрируется на любом уровне вложенности без изменения структуры относительных маршрутов.

Резюме особенностей

  • Наследование пути: дочерние маршруты автоматически комбинируются с родительским путем.
  • Модульность: вложенные маршруты позволяют группировать логику.
  • Динамика: параметры URL передаются вниз по дереву.
  • Контекст: дочерние маршруты получают контекст родителя.
  • Асинхронность: поддержка промисов и async/await на любом уровне.

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