Что такое React Router и как реализовать маршрутизацию?
Что такое React Router
React Router — стандартная библиотека маршрутизации для React. Она позволяет строить Single Page Application (SPA), где переходы между «страницами» происходят на стороне клиента: URL меняется, нужный компонент рендерится, но полная перезагрузка браузера не происходит.
Актуальная версия — React Router v6, которая существенно отличается от v5 синтаксисом и концепциями.
Основные концепции
BrowserRouter
Корневой провайдер, который подключает History API браузера. Оборачивает всё приложение:
import { BrowserRouter } from 'react-router-dom';
function App() {
return (
<BrowserRouter>
<Layout />
</BrowserRouter>
);
}
Routes и Route
Компонент Routes выбирает первый подходящий маршрут из набора Route. В v6 больше нет Switch — его заменил Routes:
import { Routes, Route } from 'react-router-dom';
function AppRoutes() {
return (
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/courses" element={<CoursesPage />} />
<Route path="/courses/:id" element={<CourseDetailPage />} />
<Route path="*" element={<NotFoundPage />} />
</Routes>
);
}
Вложенные маршруты (Nested Routes)
v6 поддерживает вложенность через дочерние Route и компонент Outlet:
function AppRoutes() {
return (
<Routes>
<Route path="/dashboard" element={<DashboardLayout />}>
{/* Outlet в DashboardLayout рендерит эти дочерние маршруты */}
<Route index element={<DashboardHome />} />
<Route path="profile" element={<ProfilePage />} />
<Route path="settings" element={<SettingsPage />} />
</Route>
</Routes>
);
}
function DashboardLayout() {
return (
<div>
<Sidebar />
<Outlet /> {/* сюда вставляется активный дочерний маршрут */}
</div>
);
}
Навигация
Для ссылок используется Link (без перезагрузки) или NavLink (с поддержкой активного состояния):
import { Link, NavLink } from 'react-router-dom';
function Nav() {
return (
<nav>
<NavLink
to="/courses"
className={({ isActive }) => isActive ? 'active' : ''}
>
Курсы
</NavLink>
</nav>
);
}
Программная навигация и хуки
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
function CourseDetailPage() {
const { id } = useParams<{ id: string }>(); // параметры пути
const [searchParams] = useSearchParams(); // query-параметры
const navigate = useNavigate(); // программный переход
const handleBack = () => navigate(-1); // назад в истории
const handleHome = () => navigate('/', { replace: true }); // без записи в историю
return <div>Курс {id}</div>;
}
Защищённые маршруты
Паттерн для авторизованных зон:
function PrivateRoute({ children }: { children: React.ReactNode }) {
const { isAuthenticated } = useAuth();
return isAuthenticated ? <>{children}</> : <Navigate to="/login" replace />;
}
// Использование
<Route
path="/dashboard"
element={
<PrivateRoute>
<DashboardLayout />
</PrivateRoute>
}
/>
Ключевые отличия v6 от v5
Switch→Routescomponent={Page}→element={<Page />}useHistory→useNavigate- Вложенные маршруты декларируются внутри родительского
Route, а не в дочернем компоненте - Относительные пути работают автоматически в дочерних
Route
Что хочет услышать интервьюер
Понимание разницы между серверной и клиентской маршрутизацией, знание что SPA не перезагружает страницу
Знание ключевых компонентов v6: BrowserRouter, Routes, Route, Link, Outlet и их роли
Умение работать с динамическими сегментами через useParams и query-параметрами через useSearchParams
Знание паттерна вложенных маршрутов с Outlet для построения layout-иерархии
Понимание как реализовать защищённые маршруты (Private Route) с редиректом на логин
Пример: Базовая настройка маршрутизации в приложении
// main.tsx
import { BrowserRouter } from 'react-router-dom';
import { App } from './App';
ReactDOM.createRoot(document.getElementById('root')!).render(
<BrowserRouter>
<App />
</BrowserRouter>
);
// App.tsx
import { Routes, Route, Navigate } from 'react-router-dom';
export function App() {
return (
<Routes>
<Route path="/" element={<Navigate to="/courses" replace />} />
<Route path="/courses" element={<CoursesPage />} />
<Route path="/courses/:id" element={<CourseDetailPage />} />
<Route
path="/dashboard"
element={
<PrivateRoute>
<DashboardLayout />
</PrivateRoute>
}
>
<Route index element={<DashboardHome />} />
<Route path="profile" element={<ProfilePage />} />
</Route>
<Route path="*" element={<NotFoundPage />} />
</Routes>
);
}
Пример: Хуки навигации и работа с параметрами
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
function CourseDetailPage() {
// Достаём динамический сегмент /courses/:id
const { id } = useParams<{ id: string }>();
// Читаем и пишем query-параметры (?tab=overview)
const [searchParams, setSearchParams] = useSearchParams();
const activeTab = searchParams.get('tab') ?? 'overview';
const navigate = useNavigate();
const handleEnroll = async () => {
await enrollToCourse(id!);
// replace: true — не добавляет запись в историю, нельзя вернуться назад
navigate('/dashboard', { replace: true });
};
return (
<div>
<h1>Курс {id}</h1>
<button onClick={() => setSearchParams({ tab: 'lessons' })}>Уроки</button>
<button onClick={handleEnroll}>Записаться</button>
</div>
);
}
Типичные ошибки
Путаница между v5 и v6: использование Switch, component=, useHistory — API, которых в v6 нет
Отсутствие fallback-маршрута path="*" — при неизвестном URL пользователь видит пустой экран
Использование тега <a> вместо <Link>, что вызывает полную перезагрузку страницы
Неправильное размещение BrowserRouter — оборачивать нужно корень приложения, а не отдельные компоненты
Дублирование маршрутов в дочерних компонентах вместо использования вложенных Route с Outlet


