Библиотека Universal Router построена вокруг
концепции маршрутов, каждый из которых может иметь собственное действие
(action). Одним из ключевых механизмов является возможность
передачи контекста, который может содержать любые данные, необходимые
для обработки запроса или рендеринга страницы.
Контекст — это объект, который передаётся в
router.resolve(context). Он может содержать:
params)query)user, auth, store)fetchData, redirect,
navigate)Пример структуры контекста:
const context = {
pathname: '/profile/123',
params: {},
query: { ref: 'dashboard' },
user: { id: 42, name: 'Alice' },
fetchData: async (url) => await fetch(url).then(res => res.json())
};
Каждый маршрут в Universal Router описывается объектом с полями
path, action и, при необходимости,
children. Контекст передаётся в action
автоматически при вызове router.resolve(context).
import UniversalRouter from 'universal-router';
const routes = [
{
path: '/profile/:id',
action: async (context) => {
const userId = context.params.id;
const userData = await context.fetchData(`/api/users/${userId}`);
return { page: 'Profile', data: userData };
}
}
];
const router = new UniversalRouter(routes);
const context = {
pathname: '/profile/123',
params: {},
fetchData: async (url) => await fetch(url).then(res => res.json())
};
router.resolve(context).then(result => {
console.log(result);
});
В этом примере context передаёт функцию
fetchData, которая используется в action для
загрузки данных пользователя. Параметры маршрута автоматически
подставляются в context.params.
Контекст можно модифицировать на лету перед вызовом
router.resolve(). Это позволяет использовать один и тот же
маршрут с разными данными или функциями:
const contextBase = {
pathname: '/profile/123',
fetchData: async (url) => await fetch(url).then(res => res.json())
};
const contextWithAuth = {
...contextBase,
user: { id: 42, name: 'Alice', role: 'admin' }
};
router.resolve(contextWithAuth);
Такой подход позволяет делать маршруты универсальными и легко расширяемыми.
Universal Router поддерживает вложенные маршруты
(children). Контекст автоматически передаётся вниз по
иерархии, что позволяет дочерним маршрутам получать доступ ко всем
данным, переданным из родителя.
const routes = [
{
path: '/dashboard',
action: (context) => ({ page: 'Dashboard' }),
children: [
{
path: 'stats',
action: (context) => {
console.log(context.user); // доступ к user из родительского контекста
return { page: 'Stats' };
}
}
]
}
];
Контекст особенно полезен при асинхронных операциях. Все данные и функции, которые необходимы для загрузки ресурсов, можно передавать через контекст, избегая глобальных переменных:
const routes = [
{
path: '/posts/:id',
action: async ({ params, fetchData }) => {
const post = await fetchData(`/api/posts/${params.id}`);
return { page: 'Post', data: post };
}
}
];
Контекст можно расширять функциями redirect или
navigate, которые будут использоваться внутри
action для управления маршрутизацией:
const context = {
pathname: '/login',
user: null,
redirect: (url) => { window.location.href = url; }
};
const routes = [
{
path: '/profile',
action: ({ user, redirect }) => {
if (!user) redirect('/login');
return { page: 'Profile' };
}
}
];
Этот подход позволяет управлять поведением маршрутов без нарушения
чистоты action.
action каждого маршрута и доступен на
всех уровнях вложенности.Передача контекста является основой гибкой архитектуры приложений с Universal Router, обеспечивая контроль над данными и поведением маршрутов без жёсткой привязки к конкретным источникам информации.