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

В Universal Router маршруты организуются в виде дерева объектов, где каждый объект представляет отдельный маршрут с набором свойств: path, action, children и других. Каждый маршрут может иметь родителя и потомков, что позволяет создавать вложенные маршруты с разной степенью детализации.

Ключевые свойства маршрута:

  • path — строка, задающая шаблон URL. Поддерживаются динамические сегменты через :param и регулярные выражения.
  • action — функция, вызываемая при совпадении маршрута. Обычно возвращает компонент, данные или редирект.
  • children — массив вложенных маршрутов, позволяющий строить дерево навигации.
  • name — опциональное имя маршрута, удобное для генерации ссылок.

Пример простого маршрута:

const routes = [
  {
    path: '/home',
    action: () => 'Главная страница'
  },
  {
    path: '/about',
    action: () => 'О нас'
  }
];

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

В Universal Router вложенность реализуется через свойство children. Это позволяет создавать маршруты типа /users/:id/profile, где /users/:id является родителем, а profile — дочерним маршрутом.

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

Особенности вложенности:

  • Дочерний маршрут наследует параметры родителя.
  • path дочернего маршрута не должен начинаться с /, иначе он будет рассматриваться как абсолютный.
  • Вложенные маршруты обрабатываются рекурсивно: Universal Router проходит дерево сверху вниз, проверяя совпадения.

Динамические сегменты и параметры

Динамические сегменты обозначаются двоеточием :. Они захватывают значения из URL и передаются в объект params функции action.

{
  path: '/posts/:postId/comments/:commentId',
  action: ({ params }) => `Пост ${params.postId}, комментарий ${params.commentId}`
}

Поддерживается использование регулярных выражений для более точного контроля над допустимыми значениями:

{
  path: '/product/:id(\\d+)',
  action: ({ params }) => `Продукт с ID ${params.id}`
}

Асинхронные действия

Universal Router позволяет action быть асинхронной функцией. Это полезно для загрузки данных перед рендерингом страницы или компонента.

{
  path: '/users/:id',
  action: async ({ params }) => {
    const response = await fetch(`/api/users/${params.id}`);
    const data = await response.json();
    return data;
  }
}

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

Использование функций match и resolveRoute

  • match: проверяет, соответствует ли маршрут текущему URL. Используется внутри Universal Router для поиска подходящего маршрута.
  • resolveRoute: выполняет action найденного маршрута и возвращает результат. Может рекурсивно обрабатывать дочерние маршруты.

Пример объединения вложенных маршрутов с асинхронной загрузкой:

const router = new UniversalRouter(routes);

router.resolve('/users/42/profile').then(result => {
  console.log(result); // 'Профиль пользователя 42'
});

Редиректы и ошибки

  • Для реализации редиректа в action можно вернуть объект { redirect: '/new-path' }.
  • Для обработки ошибок и fallback-маршрутов используется глобальный catch или маршрут с path '*'.
const routes = [
  {
    path: '/old',
    action: () => ({ redirect: '/new' })
  },
  {
    path: '*',
    action: () => 'Страница не найдена'
  }
];

Организация сложных деревьев

При больших приложениях дерево маршрутов можно структурировать по модулям:

import userRoutes from './userRoutes';
import adminRoutes from './adminRoutes';

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

Каждый модуль может содержать свои вложенные маршруты, динамические сегменты и асинхронные action. Это облегчает поддержку кода и повышает читаемость.

Итог структуры дерева маршрутов

  • Родительские и дочерние маршруты создают иерархию.
  • Динамические сегменты позволяют гибко обрабатывать параметры URL.
  • Асинхронные action обеспечивают загрузку данных.
  • Редиректы и wildcard-маршруты упрощают управление навигацией.
  • Модульное построение дерева маршрутов облегчает масштабирование приложений.

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