Пошук уроків, статей та іншого контенту
Реалізуєте програмну навігацію після дій користувача за допомогою хука useNavigate та передачі стану переходу.
Програмна навігація — це перехід на інший маршрут із JavaScript-коду у відповідь на дію користувача:
успішне надсилання форми;
завершення авторизації;
натискання кнопки;
видалення або збереження даних;
повернення на попередню сторінку.
У React Router для цього використовується хук useNavigate.
На відміну від навігації через компонент Link, програмний перехід виконується не під час рендерингу, а всередині обробника події або іншої функції.
useNavigateСпочатку імпортуємо хук:
import { useNavigate } from "react-router-dom";Потім викликаємо його всередині компонента:
const navigate = useNavigate();Результат виклику — функція, за допомогою якої можна змінювати маршрут:
navigate("/dashboard");Після виконання цього коду React Router відкриє маршрут /dashboard без перезавантаження сторінки.
Хук useNavigate можна викликати лише всередині компонента, який перебуває в контексті BrowserRouter.
Розглянемо форму входу. Після успішної перевірки даних користувача потрібно перенаправити на сторінку кабінету.
import { useState } from "react";
import { useNavigate } from "react-router-dom";
function LoginPage() {
const navigate = useNavigate();
const [email, setEmail] = useState("");
function handleSubmit(event) {
event.preventDefault();
if (!email.trim()) {
return;
}
// Після успішного входу переходимо до кабінету
navigate("/dashboard");
}
return (
<form onSubmit={handleSubmit}>
<label>
Електронна пошта
<input
type="email"
value={email}
onChange={(event) => setEmail(event.target.value)}
/>
</label>
<button type="submit">Увійти</button>
</form>
);
}
export default LoginPage;Важливо викликати event.preventDefault(), щоб браузер не перезавантажив сторінку після надсилання форми.
Разом із переходом можна передати тимчасовий стан:
navigate("/dashboard", {
state: {
message: "Вхід виконано успішно",
},
});Цей стан не додається до URL. Він передається React Router безпосередньо під час переходу.
Отримати переданий стан на цільовій сторінці можна за допомогою хука useLocation:
import { useLocation } from "react-router-dom";
function DashboardPage() {
const location = useLocation();
const message = location.state?.message;
return (
<main>
{message && <p>{message}</p>}
<h1>Особистий кабінет</h1>
</main>
);
}
export default DashboardPage;Оператор ?. потрібен тому, що сторінка може бути відкрита без переданого стану. Наприклад, користувач може безпосередньо ввести /dashboard в адресному рядку.
У наступному прикладі після надсилання форми виконується перехід на /dashboard, а разом із ним передається повідомлення.
import { useState } from "react";
import {
BrowserRouter,
Routes,
Route,
useLocation,
useNavigate,
} from "react-router-dom";
function LoginPage() {
const navigate = useNavigate();
const [email, setEmail] = useState("");
function handleSubmit(event) {
event.preventDefault();
if (!email.trim()) {
return;
}
// Передаємо повідомлення на сторінку кабінету
navigate("/dashboard", {
state: {
message: `Вітаємо, ${email}!`,
},
});
}
return (
<main>
<h1>Вхід</h1>
<form onSubmit={handleSubmit}>
<label>
Електронна пошта
<input
type="email"
value={email}
onChange={(event) => setEmail(event.target.value)}
required
/>
</label>
<button type="submit">Увійти</button>
</form>
</main>
);
}
function DashboardPage() {
const navigate = useNavigate();
const location = useLocation();
const message = location.state?.message;
function handleLogout() {
// Повертаємо користувача на сторінку входу
navigate("/login", {
replace: true,
});
}
return (
<main>
{message && <p>{message}</p>}
<h1>Особистий кабінет</h1>
<button type="button" onClick={handleLogout}>
Вийти
</button>
</main>
);
}
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/login" element={<LoginPage />} />
<Route path="/dashboard" element={<DashboardPage />} />
</Routes>
</BrowserRouter>
);
}
export default App;За замовчуванням navigate додає новий запис до історії браузера:
navigate("/dashboard");Після такого переходу натискання кнопки «Назад» поверне користувача на попередній маршрут.
Іноді попередній маршрут не має залишатися в історії. Наприклад, після виходу з кабінету користувач не повинен повертатися назад кнопкою браузера. Для цього використовують параметр replace:
navigate("/login", {
replace: true,
});У такому разі поточний запис історії замінюється новим.
navigate може отримати число. Значення -1 повертає на одну сторінку назад:
import { useNavigate } from "react-router-dom";
function DetailsPage() {
const navigate = useNavigate();
return (
<button type="button" onClick={() => navigate(-1)}>
Назад
</button>
);
}Позитивне число переміщує вперед в історії браузера, але в більшості прикладів достатньо navigate(-1) для повернення на попередню сторінку.
Стан, переданий через navigate, призначений для даних, які потрібні саме під час переходу:
navigate("/orders", {
state: {
orderCreated: true,
},
});На цільовій сторінці його можна прочитати так:
const location = useLocation();
if (location.state?.orderCreated) {
// Показати повідомлення про створення замовлення
}Такий стан має кілька особливостей:
він не відображається в адресному рядку;
він доступний після переходу в межах поточної навігації;
його може не бути після прямого відкриття маршруту;
його не слід використовувати як єдине джерело важливих даних.
Тому завжди потрібно передбачати ситуацію, коли location.state відсутній.
useNavigate поза компонентомНеправильно:
const navigate = useNavigate();
function LoginPage() {
// ...
}Хуки потрібно викликати всередині компонента:
function LoginPage() {
const navigate = useNavigate();
// ...
}BrowserRouterКомпонент із useNavigate має бути дочірнім компонентом BrowserRouter. Інакше React Router не зможе надати йому необхідний контекст.
Якщо не скасувати стандартну поведінку форми, браузер перезавантажить сторінку:
function handleSubmit(event) {
event.preventDefault();
navigate("/dashboard");
}Небезпечно розраховувати, що стан завжди існує:
const message = location.state.message;Користувач може відкрити сторінку без переходу з попереднього компонента. Безпечніше використовувати optional chaining:
const message = location.state?.message;Стан переходу не є механізмом захисту даних. Не передавайте через нього паролі, токени або іншу конфіденційну інформацію. Для навігації використовуйте лише дані, необхідні інтерфейсу.
useNavigate повертає функцію для програмної навігації.
Перехід виконується викликом navigate("/route").
Другим аргументом можна передати state.
Переданий стан читається через useLocation.
Для заміни поточного запису історії використовується { replace: true }.
navigate(-1) повертає користувача на попередній маршрут.
location.state може бути відсутнім, тому його потрібно читати безпечно.