Хранение состояния для возврата после входа

В 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.