Как реализовать масштабируемую систему маршрутизации с авторизацией и lazy loading?

Реализация масштабируемой системы маршрутизации с авторизацией и поддержкой lazy loading в React-приложении требует продуманной архитектуры, которая учитывает безопасность, производительность и удобство масштабирования. Основные компоненты такой системы включают:

1. Библиотека маршрутизации: react-router-dom

Актуальная версия React Router (v6+) предоставляет гибкий и мощный API:

  • Поддержка вложенных маршрутов.

  • Lazy-loading через React.lazy.

  • Layout-компоненты.

  • Guard-логика с element-обёртками.

  • Поддержка Loader, Action и ErrorBoundary.

2. Структура маршрутов

Маршруты можно конфигурировать в виде дерева или массива. Пример структуры:

src/
├── app/
 ├── routes.tsx
 ├── AppRouter.tsx
 └── providers/

├── pages/
 ├── Home/
 ├── Dashboard/
 ├── Login/
 └── Admin/

├── features/
├── shared/

3. Ленивые загрузки (Lazy loading)

Используем React.lazy() и Suspense для динамической подгрузки компонентов страниц:

// AppRouter.tsx
import { lazy, Suspense } from "react";
import { Routes, Route } from "react-router-dom";
const HomePage = lazy(() => import("../pages/Home"));
const LoginPage = lazy(() => import("../pages/Login"));
const DashboardPage = lazy(() => import("../pages/Dashboard"));
const AdminPage = lazy(() => import("../pages/Admin"));
export function AppRouter() {
return (
&lt;Suspense fallback={<div&gt;Загрузка...&lt;/div&gt;}>
&lt;Routes&gt;
&lt;Route path="/" element={<HomePage /&gt;} />
&lt;Route path="/login" element={<LoginPage /&gt;} />
<Route path="/dashboard" element={
&lt;ProtectedRoute&gt;
&lt;DashboardPage /&gt;
&lt;/ProtectedRoute&gt;
} />
<Route path="/admin" element={
&lt;RoleProtectedRoute role="admin"&gt;
&lt;AdminPage /&gt;
&lt;/RoleProtectedRoute&gt;
} />
&lt;/Routes&gt;
&lt;/Suspense&gt;
);
}

4. Авторизация и защита маршрутов (Route Guards)

Для защиты маршрутов создаются обёртки:

ProtectedRoute

import { Navigate, useLocation } from "react-router-dom";
import { useAuth } from "@/shared/hooks/useAuth";
export function ProtectedRoute({ children }: { children: JSX.Element }) {
const { isAuthenticated } = useAuth();
const location = useLocation();
if (!isAuthenticated) {
return &lt;Navigate to="/login" state={{ from: location }} replace /&gt;;
}
return children;
}

RoleProtectedRoute

export function RoleProtectedRoute({
role,
children,
}: {
role: string;
children: JSX.Element;
}) {
const { isAuthenticated, user } = useAuth();
const location = useLocation();
if (!isAuthenticated || user.role !== role) {
return &lt;Navigate to="/unauthorized" state={{ from: location }} replace /&gt;;
}
return children;
}

5. Хранение информации о пользователе

  • Токен аутентификации можно хранить в cookie или localStorage.

  • Данные пользователя (например, роль) — в глобальном состоянии (например, Redux или Context).

  • При запуске приложения данные подгружаются и записываются в хранилище:

useEffect(() => {
authService.getCurrentUser().then(setUser);
}, \[\]);

6. Разделение public/private маршрутов

Разделим маршруты логически:

const publicRoutes = \[
{ path: "/", element: &lt;HomePage /&gt; },
{ path: "/login", element: &lt;LoginPage /&gt; },
\];
const privateRoutes = \[
{
path: "/dashboard",
element: (
&lt;ProtectedRoute&gt;
&lt;DashboardPage /&gt;
&lt;/ProtectedRoute&gt;
),
},
{
path: "/admin",
element: (
&lt;RoleProtectedRoute role="admin"&gt;
&lt;AdminPage /&gt;
&lt;/RoleProtectedRoute&gt;
),
},
\];

Можно объединить их в AppRouter с помощью .map.

7. Layout и вложенные маршруты

React Router поддерживает layout-компоненты:
&lt;Route element={<MainLayout /&gt;}>
&lt;Route path="/" element={<HomePage /&gt;} />
&lt;Route path="/dashboard" element={<DashboardPage /&gt;} />
&lt;/Route&gt;

В MainLayout может быть Sidebar, Navbar, Outlet.

8. Error Boundary и fallback

Для обработки ошибок загрузки можно использовать Suspense + ErrorBoundary:

&lt;Suspense fallback={<LoadingScreen /&gt;}>
&lt;ErrorBoundary fallback={<ErrorFallback /&gt;}>
&lt;Routes&gt;...&lt;/Routes&gt;
&lt;/ErrorBoundary&gt;
&lt;/Suspense&gt;

9. Поддержка роли, языка и параметров

URL можно использовать с параметрами:

&lt;Route path="/profile/:id" element={<ProfilePage /&gt;} />

А в компоненте:

const { id } = useParams();

Для локализации маршрутов можно использовать i18n + конфиг pathMap или поддомены.

10. Тестирование маршрутов

Для unit-тестов:

import { MemoryRouter } from "react-router-dom";
render(
&lt;MemoryRouter initialEntries={\["/dashboard"\]}&gt;
&lt;AppRouter /&gt;
&lt;/MemoryRouter&gt;
);

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

11. Автоматическая генерация маршрутов (опционально)

В больших приложениях можно создавать маршруты автоматически из структуры файлов:

const pages = import.meta.glob("../pages/\*\*/\*.tsx");
const routes = Object.entries(pages).map((\[path, loader\]) => ({
path: pathToRoute(path), // преобразовать путь в роут
element: lazy(loader),
}));

Это снижает рутину при масштабировании.

12. SSR/SPA/CSR поддержка

Если приложение использует SSR (например, Next.js), механика авторизации и маршрутов может отличаться (middleware, getServerSideProps и т.п.).

Для SPA используется BrowserRouter, а при необходимости поддержки старых браузеров или hash-based маршрутов — HashRouter.

13. Хуки: useNavigate, useLocation, useParams

React Router предоставляет мощные хуки:

  • useNavigate() — программный переход.

  • useLocation() — текущий URL + state.

  • useParams() — параметры URL.

  • useSearchParams() — query-параметры.

Пример:

const navigate = useNavigate();
useEffect(() => {
if (user.role === "admin") {
navigate("/admin");
}
}, \[user\]);

14. Управление доступом и редиректы при авторизации

После логина можно делать редирект:

const location = useLocation();
const from = location.state?.from?.pathname || "/";
login().then(() => {
navigate(from, { replace: true });
});

Это позволяет возвращаться на страницу, которую пользователь изначально хотел открыть.