Приватные маршруты (private routes) используются для ограничения
доступа к определённым страницам приложения. Обычно это страницы, доступ
к которым должен быть только у аутентифицированного пользователя,
например, профиль, личные настройки или корзина в интернет-магазине.
Реализация приватных маршрутов в React Router требует понимания работы с
компонентами Route, Navigate и состояния
аутентификации.
1. Контроль доступа через компонент-обертку Для
приватного маршрута создается компонент, который проверяет, авторизован
ли пользователь. Если нет — происходит перенаправление на страницу входа
(/login).
Пример базового компонента приватного маршрута:
import { Navigate, Outlet } from 'react-router-dom';
function PrivateRoute({ isAuthenticated }) {
if (!isAuthenticated) {
return <Navigate to="/login" replace />;
}
return <Outlet />;
}
export default PrivateRoute;
isAuthenticated — логическое значение, отражающее
состояние аутентификации.Navigate выполняет программное перенаправление без
перезагрузки страницы.Outlet позволяет вложенным маршрутам отображаться
внутри приватного маршрута.Для организации маршрутов с React Router v6+ применяется
структура с Routes и вложенными Route.
Приватные маршруты используют обертку-компонент.
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import PrivateRoute from './PrivateRoute';
import Dashboard from './Dashboard';
import Login from './Login';
import Home from './Home';
function App({ isAuthenticated }) {
return (
<Router>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/login" element={<Login />} />
<Route element={<PrivateRoute isAuthenticated={isAuthenticated} />}>
<Route path="/dashboard" element={<Dashboard />} />
</Route>
</Routes>
</Router>
);
}
Ключевой момент: приватный маршрут оборачивает все защищенные
страницы. Если пользователь не авторизован, доступ к
/dashboard невозможен.
Для приложений с большим количеством защищенных маршрутов приватный маршрут можно использовать как родительский для группы страниц:
<Route element={<PrivateRoute isAuthenticated={isAuthenticated} />}>
<Route path="/profile" element={<Profile />} />
<Route path="/settings" element={<Settings />} />
<Route path="/orders" element={<Orders />} />
</Route>
Такой подход уменьшает дублирование кода и упрощает поддержку структуры маршрутов.
Вместо передачи пропса isAuthenticated напрямую, удобно
использовать контекст React для хранения состояния пользователя:
import { createContext, useContext, useState } from 'react';
const AuthContext = createContext();
export function AuthProvider({ children }) {
const [isAuthenticated, setIsAuthenticated] = useState(false);
const login = () => setIsAuthenticated(true);
const logout = () => setIsAuthenticated(false);
return (
<AuthContext.Provider value={{ isAuthenticated, login, logout }}>
{children}
</AuthContext.Provider>
);
}
export function useAuth() {
return useContext(AuthContext);
}
Теперь приватный маршрут можно реализовать через контекст:
import { useAuth } from './AuthContext';
import { Navigate, Outlet } from 'react-router-dom';
function PrivateRoute() {
const { isAuthenticated } = useAuth();
if (!isAuthenticated) return <Navigate to="/login" replace />;
return <Outlet />;
}
Использование контекста упрощает доступ к состоянию авторизации в любом компоненте приложения.
Чтобы вернуть пользователя на страницу, к которой он пытался получить
доступ, можно передавать параметр state в
Navigate:
import { useLocation, Navigate, Outlet } from 'react-router-dom';
import { useAuth } from './AuthContext';
function PrivateRoute() {
const { isAuthenticated } = useAuth();
const location = useLocation();
if (!isAuthenticated) {
return <Navigate to="/login" replace state={{ from: location }} />;
}
return <Outlet />;
}
На странице логина:
import { useLocation, useNavigate } from 'react-router-dom';
import { useAuth } from './AuthContext';
function Login() {
const { login } = useAuth();
const navigate = useNavigate();
const location = useLocation();
const from = location.state?.from?.pathname || '/';
const handleLogin = () => {
login();
navigate(from, { replace: true });
};
return <button onCl ick={handleLogin}>Войти</button>;
}
Такой подход обеспечивает плавный UX: пользователь возвращается на исходный защищённый маршрут после авторизации.
Для более сложных приложений можно добавлять проверку роли пользователя:
function RoleBasedRoute({ allowedRoles }) {
const { user } = useAuth();
if (!user || !allowedRoles.includes(user.role)) {
return <Navigate to="/unauthorized" replace />;
}
return <Outlet />;
}
Пример использования:
<Route element={<RoleBasedRoute allowedRoles={['admin']} />}>
<Route path="/admin" element={<AdminPanel />} />
</Route>
Таким образом, приватные маршруты можно комбинировать с ролевой моделью доступа.
Outlet для вложенных маршрутов позволяет
минимизировать дублирование.Navigate обеспечивает удобное программное
перенаправление.state при перенаправлении позволяет
реализовать «возврат к исходному маршруту» после логина.Приватные маршруты в React Router — это гибкий инструмент, позволяющий строить безопасные интерфейсы и управлять доступом к страницам приложения, не нарушая реактивную модель и SPA-архитектуру.