Avatar ·

Как программно перейти на другую страницу в React Router v6?

Всем привет! Я только начал изучать React и столкнулся с проблемой. Использую React Router v6 для навигации в приложении. Через обычные ссылки всё работает отлично, но мне нужно программно перенаправлять пользователя после определённых действий — например, после успешного входа в систему или после отправки формы. Вот мой код компонента логина: ```javascript import { useNavigate } from 'react-router-dom'; function LoginForm() { const handleSubmit = async (event) => { event.preventDefault(); const response = await fetch('/api/login', { method: 'POST', body: new FormData(event.target) }); if (response.ok) { // Вот здесь я хочу перейти на /dashboard console.log('Успешный вход! Нужно перейти на dashboard'); } }; return (
); } ``` Я пробовал использовать history.push('/dashboard'), но в v6 это не работает. Пытался использовать useHistory — тоже ошибка. Как правильно сделать программную навигацию в React Router v6? Желательно с примерами для разных ситуаций: переход после логина, редирект на 404 страницу, переход по кнопке без использования . <<>>

Программная навигация в React Router v6

В React Router v6 для программной навигации используется хук useNavigate. Он заменил старый useHistory из v5. Давайте разберём все основные сценарии.

1. Базовая навигация с useNavigate

Хук useNavigate возвращает функцию navigate, которую можно вызывать с путём или числом (для навигации по истории):

import { useNavigate } from 'react-router-dom';

function LoginForm() {
  const navigate = useNavigate();

  const handleSubmit = async (event) => {
    event.preventDefault();
    const response = await fetch('/api/login', {
      method: 'POST',
      body: new FormData(event.target)
    });
    
    if (response.ok) {
      navigate('/dashboard'); // Переход на /dashboard
    } else {
      navigate('/login-error'); // Переход на страницу ошибки
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <input name="email" type="email" placeholder="Email" />
      <input name="password" type="password" placeholder="Пароль" />
      <button type="submit">Войти</button>
    </form>
  );
}

2. Навигация с заменой истории (replace)

Если нужно заменить текущую запись в истории (например, после редиректа с логина), используйте второй параметр:

navigate('/dashboard', { replace: true });

Это полезно, чтобы пользователь не мог нажать "Назад" и вернуться на страницу логина после успешного входа.

3. Навигация по истории (вперёд/назад)

Можно передавать числа для навигации по истории браузера:

navigate(-1); // Назад
navigate(-2); // На две страницы назад
navigate(1);  // Вперёд

4. Редирект на 404 страницу

Для редиректа на страницу 404 при неверном маршруте используйте компонент Navigate:

import { Navigate } from 'react-router-dom';

function NotFoundRedirect() {
  return <Navigate to="/404" replace />;
}

// Или в маршрутизации:
<Route path="*" element={<Navigate to="/404" replace />} />

5. Навигация с передачей state

Можно передавать данные через state:

navigate('/profile', { 
  state: { userId: 123, fromLogin: true } 
});

// В компоненте Profile получаем:
const location = useLocation();
console.log(location.state.userId); // 123

6. Навигация из обычных функций (не компонентов)

Если нужно навигировать из обычной функции (например, из хранилища Redux или утилиты), создайте кастомный хук:

// Создаём фабрику навигации
let navigateFunction = null;

export function setNavigate(fn) {
  navigateFunction = fn;
}

export function navigate(path) {
  if (navigateFunction) {
    navigateFunction(path);
  }
}

// В корневом компоненте:
import { useNavigate } from 'react-router-dom';
import { setNavigate } from './navigation';

function App() {
  const navigate = useNavigate();
  setNavigate(navigate);
  // ... остальной код
}

// Теперь можно использовать из любого места:
import { navigate } from './navigation';
navigate('/dashboard');

7. Навигация в функциональных компонентах без хуков

Для классовых компонентов или случаев, когда хук недоступен, используйте компонент Navigate условно:

import { Navigate } from 'react-router-dom';

function LoginPage({ isLoggedIn }) {
  if (isLoggedIn) {
    return <Navigate to="/dashboard" replace />;
  }
  return <LoginForm />;
}

Важные замечания:

  • useNavigate можно использовать только внутри компонента, который является потомком <BrowserRouter>
  • Не используйте window.location.href — это вызывает полную перезагрузку страницы и теряет состояние React
  • Для ссылок всегда предпочитайте <Link> — он производительнее и доступнее
  • В React Router v6 нет useHistory — он полностью заменён на useNavigate

Полный рабочий пример:

import { useNavigate, Navigate, useLocation } from 'react-router-dom';

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/login" element={<LoginPage />} />
        <Route path="/dashboard" element={<Dashboard />} />
        <Route path="*" element={<Navigate to="/login" replace />} />
      </Routes>
    </BrowserRouter>
  );
}

function LoginPage() {
  const navigate = useNavigate();
  const location = useLocation();

  const handleLogin = () => {
    // После успешного логина
    navigate('/dashboard', { 
      replace: true,
      state: { from: location }
    });
  };

  return <button onClick={handleLogin}>Войти</button>;
}
<<>>

Альтернативный подход: использование компонента Navigate с условным рендерингом

Если вы предпочитаете декларативный стиль или работаете с классовыми компонентами, где хуки недоступны, можно использовать компонент Navigate из React Router v6. Он работает как условный редирект:

import { Navigate } from 'react-router-dom';

class LoginForm extends React.Component {
  state = { shouldRedirect: false };

  handleSubmit = async (e) => {
    e.preventDefault();
    // ... логика входа
    this.setState({ shouldRedirect: true });
  };

  render() {
    if (this.state.shouldRedirect) {
      return <Navigate to="/dashboard" replace />;
    }

    return (
      <form onSubmit={this.handleSubmit}>
        <input name="email" />
        <button type="submit">Войти</button>
      </form>
    );
  }
}

Этот подход удобен, когда нужно выполнить редирект на основе состояния компонента или пропсов. Компонент Navigate автоматически перенаправляет пользователя при монтировании, что делает код более предсказуемым и тестируемым.

Также можно использовать его для защиты маршрутов:

function ProtectedRoute({ children }) {
  const isAuthenticated = checkAuth();
  
  if (!isAuthenticated) {
    return <Navigate to="/login" replace />;
  }
  
  return children;
}

Главное преимущество — не нужно вызывать функции в колбэках, что упрощает отладку и делает код более реактивным. Однако для сложной логики навигации (например, переход после нескольких асинхронных операций) useNavigate остаётся более гибким решением.