Маршрутизация в React с React Router v6

Введение
React сам по себе не содержит встроенной системы маршрутизации — за это обычно отвечает библиотека React Router. В версии v6 произошла переработка алгоритма маршрутизации: добавлены автоматический ранжирующий механизм совпадений, относительные маршруты и новый API для декларативного определения маршрутов. Это делает маршрутизацию более предсказуемой и гибкой.
Короткое определение: React Router — это компонентная библиотека для управления URL, навигацией и состоянием маршрутов в React-приложениях.
Важно: статья подходит для клиентских (браузерных) React‑приложений; для серверного рендеринга и специальных случаев могут потребоваться дополнительные настройки.
Начало работы: установка и базовая настройка
- Создайте React-приложение (create-react-app, Vite или другая сборка).
- Установите пакет:
npm install react-router-dom- Оберните приложение в компонент BrowserRouter (обычно в index.jsx или main.jsx), чтобы предоставлять контекст маршрутизации всему дереву компонентов.
Пример index.jsx:
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
import { BrowserRouter as Router } from 'react-router-dom'
ReactDOM.createRoot(document.getElementById('root')).render(
,
)Примечание: BrowserRouter использует history API браузера и подходит для большинства SPA. Для приложений, где нужен базовый путь (например, при деплое в подкаталог), используйте проп baseName.
Создание маршрутов: Routes и Route
После инициализации Router определите маршруты. В v6 компонент Routes заменил старый Switch и обладает преимуществами: относительные маршруты, автоматический ранжировщик и поддержка вложенности.
Пример App.jsx:
import './App.css'
import { Routes, Route } from 'react-router-dom'
import Dashboard from './pages/Dashboard'
import About from './pages/About'
function App() {
return (
<>
} />
} />
>
)
}
export default AppПояснение: у Route теперь используется свойство element, в которое передаётся JSX-элемент. Это даёт возможность передавать пропсы и композиции компонентов напрямую.
Совет по структуре: храните страницы в папке src/pages, а мелкие маршрутизируемые фрагменты — в src/features или src/components.
Альтернативный подход: createBrowserRouter и RouterProvider
React Router рекомендует для некоторых случаев использовать createBrowserRouter — он принимает массив конфигураций маршрутов и работает вместе с RouterProvider.
Пример конфигурации в index.jsx:
import React from 'react'
import ReactDOM from 'react-dom/client'
import { createBrowserRouter, RouterProvider } from 'react-router-dom'
import App from './App.jsx'
import Dashboard from './pages/Dashboard'
import About from './pages/About'
const router = createBrowserRouter([
{
path: "/",
element: ,
},
{
path: "/dashboard",
element: ,
},
{
path: "/about",
element: ,
},
]);
ReactDOM.createRoot(document.getElementById("root")).render(
);Когда это удобно: централизованная конфигурация маршрутов, вложенные объекты с loader/action для загрузки данных и обработчиков форм (полезно при использовании data APIs внутри React Router).
Важно: RouterProvider предоставляет тот же контекст, что и BrowserRouter, но маршрутная логика формируется заранее в массиве конфигурации.
Обработка 404: маршрут “страница не найдена”
Добавьте маршрут с шаблоном “*”, чтобы поймать все несовпадения и показать дружелюбную 404‑страницу.
// используя компонент Routes
} />
// используя createBrowserRouter
{ path: "*", element: , },В NotFound.jsx реализуйте полезную страницу с ссылкой назад и, при необходимости, поиском по сайту. Звёздочка (*) — это универсальный матчер для любых путей, которые не были сопоставлены ранее.
Совет по UX: предложите пользователю навигацию назад, ссылку на главную и поле поиска — это уменьшит показатель оттока при попадании на 404.
Программная навигация: useNavigate
useNavigate позволяет навигировать программно, например, после успешной отправки формы или по клику кнопки.
import { useNavigate } from 'react-router-dom';
function About() {
const navigate = useNavigate();
const handleButtonClick = () => {
navigate("/");
};
return (
<>
{/* Остальной JSX ... */}
>
);
}
export default About;Подсказка: navigate поддерживает push/replace через второй аргумент: navigate(‘/path’, { replace: true }) — полезно для предотвращения возврата назад к странице логина после редиректа.
Отдельно: useNavigation (состояние навигации)
useNavigation даёт информацию о текущем состоянии навигации (loading, submitting и т.д.). Это не то же самое, что useNavigate — одна функция управляет навигацией, другая — даёт состояние.
Пример кнопки с учётом состояния навигации:
import { useNavigation } from "react-router-dom";
function SubmitButton() {
const navigation = useNavigation();
const buttonText =
navigation.state === "submitting"
? "Saving..."
: navigation.state === "loading"
? "Saved!"
: "Go";
return ;
}Когда использовать: показывайте спиннеры, блокируйте повторную отправку форм, или отображайте прогресс при загрузке ресурсов, связанных с навигацией.
Использование useRoutes для декларативного маршрутизирования внутри компонента
useRoutes позволяет определить маршруты как массив объектов прямо внутри компонента и вернуть результат сопоставления.
import { useRoutes } from 'react-router-dom';
import Dashboard from './Dashboard';
import About from './About';
const routes = [
{
path: '/',
element: ,
},
{
path: '/about',
element: ,
},
];
function App() {
const routeResult = useRoutes(routes);
return routeResult;
}
export default App;Плюсы: гибкость, возможность динамически формировать маршруты (например, по ролям пользователя) и легче тестировать логику маршрутизации.
Советы по организации и масштабированию маршрутов
- Разделяйте маршруты по фичам: src/features/
/routes.js. - Используйте ленивую загрузку компонентов (React.lazy + Suspense) для крупных страниц.
- Для вложенных экранов применяйте вложенные Route-ы и outlet.
- Централизуйте обработку 404 и общих ошибок (ErrorBoundary) на уровне маршрутизатора.
Пример lazy:
const Dashboard = React.lazy(() => import('./pages/Dashboard'));
// внутри Routes
}> } /> Ментальные модели и эвристики
- Маршрут = правило соответствия URL → компонент.
- Routes ранжирует совпадения по специфичности: более конкретные пути выигрывают у общих.
- element содержит JSX, а не референс на компонент.
- createBrowserRouter — декларативная карта маршрутов; BrowserRouter/Routes — более императивный/компонентный подход.
Эвристика выбора: если у вас много вложенных маршрутов с загрузкой данных (loaders/actions), используйте createBrowserRouter; для простых SPA подойдёт BrowserRouter + Routes.
Когда React Router v6 может не подойти (контрпримеры)
- Полностью статический сайт без клиентской навигации — можно обойтись без React Router.
- Проекты, где сервер генерирует все пути и нужен SSR с кастомной логикой — требуется дополнительная конфигурация и интеграция (React Router поддерживает SSR, но это отдельная настройка).
- Маленькие виджеты в многостраничном приложении, где глобальная навигация не требуется — явная маршрутизация на уровне страницы проще.
Миграция с React Router v5 на v6 — практические советы
- Замените Switch на Routes.
- Убедитесь, что Route использует prop element с JSX, а не component. Пример:
} path=”/“ />. - Проверьте вложенные маршруты: в v6 порядок важен меньше, но синтаксис вложенности другой.
- Замените useHistory на useNavigate.
- Если использовали path=”/users/:id?” с опциональным параметром — перепроверьте поведение; в некоторых случаях стоит явно прописать альтернативные маршруты.
Короткая методика миграции:
- Обновите пакеты и выполните тесты.
- Замените Switch → Routes и component → element.
- Исправьте хуки (useHistory → useNavigate).
- Протестируйте edge-case маршруты и 404.
Чек-листы (роль‑ориентированные)
Разработчик:
- Установлен react-router-dom точной версии.
- Router обёрнут на верхнем уровне приложения.
- Маршруты работают локально и через режим history.
- Добавлена 404-страница.
Тестировщик QA:
- Навигация кнопками и ссылками возвращает ожидаемый URL.
- Back/Forward (история) ведёт корректно.
- Поведение useNavigate при replace/push проверено.
- Показатели загрузки при useNavigation корректны.
Продукт/контент:
- Важно ли включать базовый путь (baseName) для деплоя?
- Все публичные URL описаны в документации.
Сниппет: быстрый шаблон маршрутов с вложенностью и ошибкой
import { BrowserRouter, Routes, Route, Outlet, Link } from 'react-router-dom'
function Layout() {
return (
<>
>
)
}
function AppRouter() {
return (
}>
} />
} />
} />
);
}Тест-кейсы и критерии приёмки
Критерии приёмки базового маршрутизатора:
- При переходе по ссылке URL меняется и отрисовывается соответствующий компонент.
- Нажатие назад/вперёд корректно восстанавливает состояние приложения.
- Некорректный URL ведёт на NotFound.
- Навигация программно через useNavigate работает для push и replace.
Риски и рекомендации по безопасности
- Не вставляйте значения из URL напрямую в innerHTML без валидации.
- При авторизации/роли: защищайте приватные маршруты с проверкой аутентификации (редирект на /login).
- При использовании loader/action убедитесь, что время отклика не раскрывает чувствительные данные.
Локальные особенности и советы по деплою
- Если деплойите приложение в подкаталог (например, example.com/app), укажите basename в BrowserRouter или настройте RouterProvider соответствующим образом.
- Для статического хостинга (Netlify, GitHub Pages) убедитесь, что сервер перенаправляет все запросы на index.html (SPA fallback).
Частые ошибки и их решения
- Ошибка: маршруты не рендерятся — проверьте, что приложение действительно обёрнуто в Router.
- Ошибка: ссылки ведут на новую страницу (полная перезагрузка) — используйте Link из react-router-dom вместо .
- Ошибка: неправильный порядок маршрутов — в v6 порядок важен меньше, но специфичные маршруты всё равно должны быть определены.
FAQ
Что выбрать: BrowserRouter или createBrowserRouter?
Выбор зависит от структуры: для централизованных конфигураций маршрутов с loader/action удобнее createBrowserRouter; для простых случаев подойдёт BrowserRouter + Routes.
Как правильно сделать приватный маршрут (только для авторизованных пользователей)?
Создайте компонент-обёртку (ProtectedRoute), который проверяет состояние аутентификации и либо рендерит Outlet, либо делает navigate(‘/login’).
Можно ли использовать nested routes с useRoutes?
Да, useRoutes поддерживает вложенные объекты маршрутов и работает аналогично компонентному подходу.
Краткое резюме
- React Router v6 упрощает маршрутизацию: Routes, useNavigate, useNavigation и createBrowserRouter — ключевые концепции.
- Выберите подходящую стратегию (компонентный или декларативный) в зависимости от архитектуры проекта.
- Тестируйте 404, навигацию истории и защиту приватных маршрутов.
Важно: начните с базовой настройки и постепенно добавляйте loaders, actions и ленивую загрузку — это позволит избежать ошибок на ранних этапах.
Источники: официальная документация React Router и практические паттерны сообщества.