Как программно перейти на другую страницу в React Router v6?
Программная навигация в 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 остаётся более гибким решением.