useBlocker — это низкоуровневый хук библиотеки React
Router, предназначенный для управления навигацией и возможности
блокировать переходы между маршрутами. Он позволяет реализовать логику,
когда пользователь пытается покинуть текущую страницу, но нужно сначала
выполнить определённые проверки, например, подтвердить потерю
несохранённых данных или предотвратить случайный уход со страницы
формы.
В React Router маршруты и навигация управляются объектом истории.
Когда происходит переход (например, вызов navigate("/home")
или клик по <Link>), React Router инициирует процесс
смены маршрута. useBlocker позволяет вмешаться в этот
процесс, предоставляя контроль над навигацией до того, как она
завершится.
Синтаксис базового использования:
import { useBlocker } from "react-router-dom";
function MyComponent() {
const blocker = useBlocker((tx) => {
if (!window.confirm("Вы действительно хотите покинуть страницу?")) {
tx.retry(); // Продолжение навигации после подтверждения
}
});
return null;
}
retry() и
cancel().Хук вызывается при каждой попытке изменения маршрута, независимо от
того, инициирована ли она программно через navigate или
через пользовательское взаимодействие с <Link>.
Наиболее распространённый сценарий использования
useBlocker — предотвращение ухода со страницы с
несохранёнными данными. Пример интеграции с формой:
import { useBlocker } from "react-router-dom";
import { useState, useEffect } from "react";
function FormPage() {
const [isDirty, setIsDirty] = useState(false);
const blocker = useBlocker((tx) => {
if (isDirty) {
const confirmLeave = window.confirm(
"У вас есть несохранённые изменения. Вы уверены, что хотите покинуть страницу?"
);
if (confirmLeave) tx.retry();
} else {
tx.retry();
}
});
return (
<form>
<input
type="text"
onCha nge={() => setIsDirty(true)}
placeholder="Введите данные"
/>
</form>
);
}
Ключевые моменты:
isDirty) перед блокировкой
навигации.tx.retry() после подтверждения пользователя для
продолжения перехода.useBlocker блокирует не только пользовательские клики по
ссылкам, но и программные вызовы navigate(). Это позволяет
централизованно управлять всеми сценариями навигации:
import { useNavigate, useBlocker } from "react-router-dom";
function Dashboard() {
const navigate = useNavigate();
useBlocker((tx) => {
if (!window.confirm("Покинуть страницу?")) {
// Отмена перехода
} else {
tx.retry();
}
});
return <button onCl ick={() => navigate("/settings")}>Перейти в настройки</button>;
}
Блокировка действует независимо от того, инициирована ли навигация
через <Link> или через кнопку с
navigate.
Синхронность и асинхронность
useBlocker работает синхронно для вызова подтверждений
(например, window.confirm). Для асинхронных проверок нужно
аккуратно управлять состоянием и запускать навигацию через
tx.retry() после завершения проверки.
Множественные блокировки Если на странице подключено несколько блокеров, React Router выполняет их по порядку. Отмена хотя бы одного блокера предотвращает навигацию полностью.
Не блокирует перезагрузку страницы или закрытие
вкладки Для обработки этих сценариев используется нативное
событие beforeunload в сочетании с
useEffect.
Совместимость с React Router v6+ Хук
useBlocker доступен в новых версиях React Router, заменяя
устаревшие подходы с Prompt.
useBlocker только на страницах, где есть
риск потери данных или нежелательных переходов.Пример структурирования:
function confirmNavigation(isDirty, tx) {
if (isDirty) {
const confirmLeave = window.confirm(
"У вас есть несохранённые изменения. Вы уверены, что хотите покинуть страницу?"
);
if (confirmLeave) tx.retry();
} else {
tx.retry();
}
}
function FormPage() {
const [isDirty, setIsDirty] = useState(false);
useBlocker((tx) => confirmNavigation(isDirty, tx));
}
Такой подход упрощает тестирование и поддержку кода при большом количестве форм или страниц с блокировками.
useBlocker является мощным инструментом для контроля
навигации в React Router, позволяя предотвращать нежелательные переходы
и обеспечивать сохранность данных пользователя. Его использование
обеспечивает безопасную и предсказуемую работу приложений, где важен
контроль над маршрутизацией.