Конфигурационная маршрутизация в React Router предоставляет
возможность описывать все маршруты приложения централизованно в виде
структуры данных, а не полагаться на вложенные JSX-компоненты
<Route>. Такой подход облегчает управление сложными
приложениями с большим числом маршрутов, позволяет динамически
генерировать маршруты и упрощает интеграцию с системами авторизации и
ленивой загрузки.
В React Router маршруты конфигурируются через массив объектов, где
каждый объект описывает путь (path), компонент
(element) и дополнительные параметры, такие как
children для вложенных маршрутов или loader
для предварительной загрузки данных. Пример базовой структуры:
const routes = [
{
path: '/',
element: <HomePage />,
},
{
path: 'about',
element: <AboutPage />,
},
{
path: 'dashboard',
element: <DashboardLayout />,
children: [
{ path: 'stats', element: <StatsPage /> },
{ path: 'settings', element: <SettingsPage /> },
],
},
];
Ключевые моменты:
path указывает URL-адрес маршрута.element задаёт компонент, который будет отрисован.children содержит вложенные маршруты, формируя
иерархию.После определения конфигурации маршрутов необходимо создать
маршрутизатор с помощью функции createBrowserRouter или
createHashRouter в зависимости от используемого типа
истории.
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
const router = createBrowserRouter(routes);
function App() {
return <RouterProvider router={router} />;
}
Особенности RouterProvider:
Вложенные маршруты позволяют использовать общие макеты и
навигационные элементы. Компонент верхнего уровня (element)
может включать <Outlet />, который будет рендерить
дочерние маршруты:
function DashboardLayout() {
return (
<div>
<Sidebar />
<main>
<Outlet />
</main>
</div>
);
}
const routes = [
{
path: 'dashboard',
element: <DashboardLayout />,
children: [
{ path: 'stats', element: <StatsPage /> },
{ path: 'settings', element: <SettingsPage /> },
],
},
];
Использование <Outlet /> делает маршруты
модульными и облегчает повторное использование макетов.
Для оптимизации загрузки больших приложений React Router поддерживает
ленивый импорт через React.lazy и Suspense. В
конфигурации маршрутов это выглядит следующим образом:
import { lazy, Suspense } from 'react';
const StatsPage = lazy(() => import('./pages/StatsPage'));
const SettingsPage = lazy(() => import('./pages/SettingsPage'));
const routes = [
{
path: 'dashboard',
element: <DashboardLayout />,
children: [
{
path: 'stats',
element: (
<Suspense fallback={<div>Загрузка...</div>}>
<StatsPage />
</Suspense>
),
},
{
path: 'settings',
element: (
<Suspense fallback={<div>Загрузка...</div>}>
<SettingsPage />
</Suspense>
),
},
],
},
];
Вывод: ленивый импорт снижает начальный вес бандла и ускоряет загрузку страницы.
React Router предоставляет возможность асинхронной предзагрузки
данных перед рендером маршрута через функцию loader. Она
возвращает промис, данные которого будут доступны в компоненте через хук
useLoaderData:
import { useLoaderData } from 'react-router-dom';
function StatsPage() {
const data = useLoaderData();
return <div>Статистика: {JSON.stringify(data)}</div>;
}
const routes = [
{
path: 'dashboard/stats',
element: <StatsPage />,
loader: async () => {
const response = await fetch('/api/stats');
return response.json();
},
},
];
Преимущества использования loader:
useEffect для
каждой страницы.Конфигурационная маршрутизация упрощает реализацию контроля доступа
через обертки (wrapper) или условный рендеринг:
function ProtectedRoute({ element }) {
const isAuthenticated = /* логика проверки авторизации */;
return isAuthenticated ? element : <Navigate to="/login" />;
}
const routes = [
{
path: 'dashboard',
element: <ProtectedRoute element={<DashboardLayout />} />,
children: [
{ path: 'stats', element: <StatsPage /> },
{ path: 'settings', element: <SettingsPage /> },
],
},
];
Такой подход позволяет централизованно управлять доступом к нескольким маршрутам без дублирования логики.
Конфигурация поддерживает указание компонента для отображения ошибок
(errorElement) на уровне маршрута:
const routes = [
{
path: 'dashboard',
element: <DashboardLayout />,
errorElement: <ErrorPage />,
children: [
{ path: 'stats', element: <StatsPage /> },
{ path: 'settings', element: <SettingsPage /> },
],
},
];
Особенности:
errorElement рендерится при сбое loader
или ошибки компонента.Маршруты могут содержать динамические сегменты с использованием
двоеточия (:):
const routes = [
{
path: 'users/:userId',
element: <UserPage />,
},
];
Доступ к параметрам осуществляется через хук
useParams:
import { useParams } from 'react-router-dom';
function UserPage() {
const { userId } = useParams();
return <div>Профиль пользователя: {userId}</div>;
}
Примечания:
loader для предзагрузки данных
конкретного пользователя.Для крупных проектов рекомендуется использовать следующую организацию:
routes.js) с
массивом объектов маршрутов.<Outlet /> для повторно используемых
компонентов интерфейса.loader для асинхронной загрузки данных.errorElement.Такой подход обеспечивает масштабируемость, упрощает поддержку и тестирование маршрутизации, а также облегчает добавление новых функциональных блоков без изменения основной логики приложения.