В React Router управление доступом к защищённым маршрутам и
сохранение состояния при перенаправлениях после аутентификации
реализуется с помощью объекта state в маршрутах и
useLocation. Это позволяет пользователю
возвращаться на страницу, на которую он изначально хотел попасть, после
успешного входа в систему.
Когда пользователь пытается открыть защищённый маршрут, чаще всего выполняется проверка авторизации. Если пользователь не авторизован, его перенаправляют на страницу входа. Важно при этом сохранить информацию о первоначальном местоположении:
import { Navigate, useLocation } from 'react-router-dom';
function RequireAuth({ children, isAuthenticated }) {
const location = useLocation();
if (!isAuthenticated) {
return <Navigate to="/login" state={{ from: location }} replace />;
}
return children;
}
Разбор ключевых моментов:
useLocation() возвращает объект текущего маршрута,
включая путь и параметры.state={{ from: location }} информация о
маршруте сохраняется для использования после входа.replace предотвращает создание лишней записи в
истории браузера, что делает поведение кнопки «назад» более
предсказуемым.На странице входа состояние можно получить с помощью хука
useLocation и использовать его для перенаправления после
успешной аутентификации:
import { useNavigate, useLocation } from 'react-router-dom';
function Login({ authenticate }) {
const navigate = useNavigate();
const location = useLocation();
const from = location.state?.from?.pathname || '/';
const handleLogin = async () => {
await authenticate();
navigate(from, { replace: true });
};
return (
<button onCl ick={handleLogin}>Войти</button>
);
}
Разбор ключевых моментов:
location.state?.from?.pathname извлекает путь, на
который нужно вернуть пользователя.'/'.navigate(from, { replace: true }) гарантирует
корректную работу истории браузера.При использовании вложенных маршрутов важно корректно сохранять путь
полностью, включая параметры и query-строку. Для этого можно передавать
объект location целиком:
<Navigate to="/login" state={{ from: location }} replace />
При этом location включает:
pathname — путь маршрута;search — строку запроса
(?param=value);hash — хэш-фрагмент (#section).Это позволяет возвращать пользователя на точное место, где он был до перенаправления.
Для более сложных приложений можно использовать контекст авторизации, который хранит текущее состояние пользователя и путь для возврата. Пример контекста:
import { createContext, useContext, useState } from 'react';
import { useLocation } from 'react-router-dom';
const AuthContext = createContext();
export function AuthProvider({ children }) {
const [user, setUser] = useState(null);
const location = useLocation();
const [redirectPath, setRedirectPath] = useState('/');
const login = (userData) => {
setUser(userData);
setRedirectPath(location.state?.from?.pathname || '/');
};
return (
<AuthContext.Provider value={{ user, login, redirectPath }}>
{children}
</AuthContext.Provider>
);
}
export const useAuth = () => useContext(AuthContext);
Преимущества такого подхода:
replace: true при перенаправлении
после входа, чтобы кнопка «назад» не возвращала на страницу логина.location, если маршруты
содержат query-параметры или хэш, чтобы возврат был точным.state в маршрутах.Хранение состояния для возврата после входа обеспечивает плавный пользовательский опыт, сохраняет контекст навигации и предотвращает потерю данных при авторизации, что особенно важно в современных SPA на React.