Universal Router — это легковесная библиотека для
маршрутизации, которая позволяет создавать динамические маршруты и
обрабатывать их через функцию resolve. При работе с React
основной задачей становится соединение маршрутов с компонентами,
обеспечивая динамическое отображение контента на основе URL.
Маршруты в Universal Router определяются массивом объектов, каждый из
которых содержит путь и функцию action, возвращающую
компонент для рендеринга.
import UniversalRouter from 'universal-router';
import HomePage from './pages/HomePage';
import AboutPage from './pages/AboutPage';
import UserPage from './pages/UserPage';
const routes = [
{
path: '/',
action: () => <HomePage />
},
{
path: '/about',
action: () => <AboutPage />
},
{
path: '/user/:id',
action: ({ params }) => <UserPage userId={params.id} />
}
];
const router = new UniversalRouter(routes);
В path можно использовать динамические сегменты,
обозначенные через :param, которые Universal Router
автоматически передаёт в объект params.
В React переходы между маршрутами обычно реализуются через
history API или через обёртки, интегрированные с
библиотеками типа react-router-dom. С Universal Router
можно управлять навигацией вручную, вызывая router.resolve
с нужным URL.
import { useState, useEffect } from 'react';
function App() {
const [component, setComponent] = useState(null);
const handleNavigation = async (pathname) => {
const routeComponent = await router.resolve({ pathname });
setComponent(routeComponent);
};
useEffect(() => {
handleNavigation(window.location.pathname);
const onPopSt ate = () => handleNavigation(window.location.pathname);
window.addEventListener('popstate', onPopState);
return () => window.removeEventListener('popstate', onPopState);
}, []);
return (
<div>
<nav>
<button onCl ick={() => { window.history.pushState({}, '', '/'); handleNavigation('/'); }}>Home</button>
<button onCl ick={() => { window.history.pushState({}, '', '/about'); handleNavigation('/about'); }}>About</button>
<button onCl ick={() => { window.history.pushState({}, '', '/user/42'); handleNavigation('/user/42'); }}>User 42</button>
</nav>
<main>{component}</main>
</div>
);
}
Ключевые моменты:
router.resolve({ pathname }) возвращает компонент,
соответствующий текущему маршруту.popstate событие позволяет отслеживать изменения
истории браузера.window.history.pushState обновляет URL без полной
перезагрузки страницы.Universal Router поддерживает иерархические маршруты. Для React это позволяет создавать компоненты-контейнеры, которые рендерят дочерние компоненты в зависимости от вложенного маршрута.
const routes = [
{
path: '/dashboard',
action: () => <DashboardLayout />,
children: [
{
path: '/stats',
action: () => <StatsPage />
},
{
path: '/settings',
action: () => <SettingsPage />
}
]
}
];
Внутри DashboardLayout можно использовать отдельный
вызов router.resolve для рендеринга дочерних компонентов на
основе текущего подмаршрута.
Universal Router позволяет использовать асинхронные функции в
action. Это удобно для загрузки данных перед отображением
компонента.
const routes = [
{
path: '/posts/:id',
action: async ({ params }) => {
const response = await fetch(`/api/posts/${params.id}`);
const post = await response.json();
return <PostPage post={post} />;
}
}
];
Преимущества:
Для SSR Universal Router предоставляет простой способ рендеринга React-компонентов на сервере, возвращая HTML строку.
import { renderToString } from 'react-dom/server';
async function handleRequest(url) {
const component = await router.resolve({ pathname: url });
const html = renderToString(component);
return html;
}
Таким образом, один и тот же набор маршрутов может использоваться и на клиенте, и на сервере, обеспечивая согласованность маршрутизации.
router.resolve для дочерних
компонентов.history.pushState и popstate
для навигации без перезагрузки страницы.Интеграция Universal Router с React обеспечивает гибкую маршрутизацию, позволяя строить динамичные приложения с поддержкой асинхронной загрузки данных и серверного рендеринга.