Доступ к параметрам в action

В библиотеке Universal Router ключевой компонент маршрутизации — это объект маршрута, у которого определяется функция action. Именно в action происходит обработка запроса и возврат результата в зависимости от URL. Для полноценного использования маршрутов необходимо понимать, как получать параметры маршрута, включая как динамические сегменты, так и query-параметры.

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

Динамический сегмент в пути определяется с помощью двоеточия : перед именем параметра. Например:

const routes = [
  {
    path: '/users/:id',
    action: ({ params }) => {
      return `Пользователь с ID: ${params.id}`;
    }
  }
];

В данном примере параметр id доступен в объекте params, который передается в функцию action.

Особенности работы с динамическими сегментами:

  • Параметры всегда доступны через объект params.
  • Имя параметра соответствует имени сегмента после двоеточия.
  • Значения параметров автоматически декодируются (например, %20 преобразуется в пробел).

Пример с несколькими параметрами:

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

Здесь params.postId и params.commentId содержат соответствующие значения из URL.

Query-параметры

Universal Router не предоставляет прямого объекта query, однако их можно извлечь из location при передаче в маршрутизатор.

import UniversalRouter from 'universal-router';

const routes = [
  {
    path: '/search',
    action: ({ query }) => {
      return `Поиск по запросу: ${query.q}`;
    }
  }
];

const router = new UniversalRouter(routes, {
  context: {
    query: new URLSearchParams(location.search)
  }
});

router.resolve('/search?q=javascript').then(console.log);

Важно: query здесь создается вручную через URLSearchParams, так как Universal Router не делает это автоматически. Это позволяет гибко использовать любые параметры GET-запроса.

Параметры с регулярными выражениями

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

const routes = [
  {
    path: '/product/:id(\\d+)',
    action: ({ params }) => {
      return `Продукт с числовым ID: ${params.id}`;
    }
  }
];

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

Наследование и вложенные маршруты

При вложенных маршрутах параметры передаются в action каждого уровня. Например:

const routes = [
  {
    path: '/users/:userId',
    action: ({ params, next }) => {
      console.log(`ID пользователя: ${params.userId}`);
      return next();
    },
    children: [
      {
        path: 'profile',
        action: ({ params }) => {
          return `Профиль пользователя ${params.userId}`;
        }
      }
    ]
  }
];
  • params.userId доступен как на уровне родителя, так и на уровне дочернего маршрута.
  • Функция next() вызывает обработку дочернего маршрута.

Использование context для передачи данных

action принимает не только params, но и объект context, который может содержать любые данные, переданные при инициализации маршрутизатора.

const router = new UniversalRouter(routes, { context: { userRole: 'admin' } });

const routes = [
  {
    path: '/dashboard',
    action: ({ context }) => {
      if (context.userRole !== 'admin') {
        return 'Доступ запрещен';
      }
      return 'Панель администратора';
    }
  }
];

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

Рекомендации по работе с параметрами

  • Всегда проверять наличие параметров: params.id может быть undefined.
  • Использовать регулярные выражения для критичных параметров (например, ID).
  • Вложенные маршруты автоматически наследуют параметры родителя.
  • Для query-параметров использовать URLSearchParams или собственный парсер.
  • Контекст удобно применять для передачи глобальных данных без polluting глобального состояния.

Пример комплексного маршрута

const routes = [
  {
    path: '/users/:userId',
    action: ({ params, context, next }) => {
      console.log(`User ID: ${params.userId}`);
      return next();
    },
    children: [
      {
        path: 'settings',
        action: ({ params, context }) => {
          if (!context.isAuthenticated) return 'Вход необходим';
          return `Настройки пользователя ${params.userId}`;
        }
      }
    ]
  }
];

const router = new UniversalRouter(routes, { context: { isAuthenticated: true } });

router.resolve('/users/42/settings').then(console.log);

В этом примере одновременно используются:

  • Динамический сегмент :userId
  • Наследование параметров в дочернем маршруте
  • Контекст приложения для проверки аутентификации

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