Universal Router — это легковесная и гибкая библиотека для маршрутизации в JavaScript, которая позволяет организовать управление навигацией в приложениях любого масштаба. Одним из ключевых аспектов является переиспользование компонентов, что обеспечивает консистентность, уменьшает дублирование кода и повышает поддерживаемость проекта.
В Universal Router маршрут определяется объектом с ключами
path и action. Значение action
часто является функцией, которая возвращает компонент или результат его
рендеринга. Для переиспользования компонентов важно строить маршруты
так, чтобы один и тот же компонент мог обслуживать несколько
маршрутов с разными параметрами.
import UniversalRouter from 'universal-router';
import HomePage from './components/HomePage';
import UserPage from './components/UserPage';
const routes = [
{ path: '/', action: () => HomePage() },
{ path: '/user/:id', action: ({ params }) => UserPage(params) }
];
const router = new UniversalRouter(routes);
В этом примере UserPage может быть использован для любых
пользователей, благодаря параметру id. Такой подход
позволяет не дублировать логику отображения, а лишь
передавать разные данные через параметры.
Компоненты в Universal Router могут получать контекст, который содержит дополнительные данные, такие как состояние приложения, функции навигации или настройки. Это делает их более универсальными и переиспользуемыми.
const routes = [
{
path: '/dashboard',
action: (context) => Dashboard(context)
},
{
path: '/settings',
action: (context) => Settings(context)
}
];
const router = new UniversalRouter(routes, { context: { user: currentUser } });
Контекст позволяет компоненту не зависеть от глобальных переменных и использовать один и тот же функционал в разных частях приложения. Это основной принцип повторного использования компонентов.
Universal Router поддерживает вложенные маршруты, что позволяет строить композицию компонентов. Один компонент может включать другие, а маршрутизация автоматически определяет, какой компонент и в каком месте рендерить.
const routes = [
{
path: '/admin',
action: ({ next }) => AdminLayout({ content: next() }),
children: [
{ path: '/users', action: () => UsersPage() },
{ path: '/reports', action: () => ReportsPage() }
]
}
];
Здесь AdminLayout используется для всех дочерних
маршрутов /admin/*, а конкретный контент подставляется
через вызов next(). Такой подход позволяет
разделить структуру страницы и контент, делая
компоненты максимально универсальными.
Иногда один компонент нужен для разных путей, например, для страниц с фильтрами или параметрами поиска. В Universal Router можно использовать регулярные выражения или массивы путей, чтобы направлять их на один и тот же компонент.
const routes = [
{
path: ['/search', '/search/:query'],
action: ({ params }) => SearchPage(params)
}
];
В этом примере SearchPage будет использоваться как для
/search, так и для /search/something, что
сокращает количество компонентов и упрощает поддержку.
Для больших приложений важно загружать компоненты только при
необходимости, сохраняя при этом возможность переиспользования.
Universal Router поддерживает асинхронные функции в action,
что позволяет динамически импортировать компоненты.
const routes = [
{
path: '/profile',
action: async () => {
const { default: ProfilePage } = await import('./components/ProfilePage');
return ProfilePage();
}
}
];
Асинхронная загрузка позволяет использовать один и тот же компонент в разных маршрутах без увеличения начального объёма бандла.
Для максимального переиспользования компонентов рекомендуется создавать обобщённые компоненты, которые получают все различия через props или контекст, вместо создания уникальных компонентов для каждой страницы.
function ItemPage({ type, id }) {
return fetchItemData(type, id).then(data => renderItem(data));
}
const routes = [
{ path: '/products/:id', action: ({ params }) => ItemPage({ type: 'product', ...params }) },
{ path: '/articles/:id', action: ({ params }) => ItemPage({ type: 'article', ...params }) }
];
Такой подход позволяет использовать одну компонентную логику для разных сущностей, снижая дублирование кода и облегчая сопровождение приложения.
Universal Router поддерживает middleware через вложенные вызовы
next(). Это позволяет переиспользовать общую логику
для нескольких маршрутов, например, авторизацию, логирование
или предзагрузку данных.
const authMiddleware = async (context, next) => {
if (!context.user) throw new Error('Unauthorized');
return next();
};
const routes = [
{
path: '/dashboard',
action: authMiddleware,
children: [
{ path: '/', action: () => DashboardPage() }
]
}
];
Middleware можно применять к любым компонентам, обеспечивая повторное использование функционала без изменения самих компонентов.
Эти принципы позволяют строить архитектуру, где компоненты остаются максимально универсальными, легко тестируемыми и легко интегрируемыми в разные части приложения.