Вопрос или проблема
Я делаю проект на React и TypeScript. Я не могу найти, как остановить пользователя от перехода на другую страницу, если есть несохранённые изменения. Чтобы прояснить, я понимаю, как сделать остальное, мне просто нужно что-то, что остановит процесс, пока не получит подтверждение от пользователя. Буду признателен за ссылки на решения для V6 React-Router. Также я готов рассмотреть любые другие варианты вместо React-Router для решения этой проблемы. Я использовал BeforeUnloadEvent, но он работает только если пользователь перезагружает страницу или переходит на другой сайт. Если пользователь меняет страницы внутри приложения, это не работает.
Я использую:
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-router-dom": "^6.26.2",
"react-scripts": "^5.0.1",
"typescript": "^5.6.2"
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
Я пробовал разные useEffects, что-то вроде:
useEffect(() => {
if (isDirty) {
setIsOpen(true);
setNextLocation(location.pathname);
}
}, [location.pathname]);
Но я не понимаю, как добавить туда “остановить или приостановить навигацию”. Поскольку это v6, многие решения, которые работали в интернете, не работают для него, такие как Prompt, usePrompt, .listen, .block, BeforeUnload. Также я пробовал
useBeforeUnload(
useCallback(e => {
if (isDirty) {
e.preventDefault();
return '';
}
}, [isDirty])
);
но это тоже не остановит навигацию (это делает то же, что и BeforeUnloadEvent).
может попробовать реализовать пользовательский хук, который использует хук useEffect вместе с подходом usePrompt??
Ответ или решение
Для предотвращения навигации пользователя на другую страницу при наличии несохраненных изменений в приложении на React с использованием React Router v6, вы можете реализовать собственный хук и механизм проверки навигации. В данной инструкции я проведу вас через этот процесс.
Шаг 1: Создание пользовательского хука для управления навигацией
Создайте файл usePrompt.ts
, который будет содержать логику для блокировки навигации:
import { useEffect } from 'react';
import { useLocation, useNavigate } from 'react-router-dom';
const usePrompt = (message: string, when: boolean) => {
const navigate = useNavigate();
const location = useLocation();
const handleBlockedNavigation = (e: BeforeUnloadEvent | any) => {
if (when) {
e.preventDefault();
return (e.returnValue = message);
}
};
useEffect(() => {
window.addEventListener('beforeunload', handleBlockedNavigation);
return () => {
window.removeEventListener('beforeunload', handleBlockedNavigation);
};
}, [when]);
useEffect(() => {
const unblock = navigate(location.pathname, { replace: true }) // изменения необходимы для создания хуков
return () => {
unblock(); // освобождаем ресурс блокировки
}
}, [location]);
useEffect(() => {
if (when) {
const confirmTransition = (e: PopStateEvent) => {
if (when && !window.confirm(message)) {
e.preventDefault();
navigate(location.pathname); // возвращаем пользователя на текущую страницу
}
};
window.onpopstate = confirmTransition;
return () => {
window.onpopstate = null;
};
}
}, [when, message, navigate, location]);
};
export default usePrompt;
Шаг 2: Использование хука в компоненте
Теперь вы можете использовать данный хук в нужном компоненте, где необходимо предупредить пользователя о несохраненных изменениях:
import React, { useState } from 'react';
import usePrompt from './usePrompt';
const MyComponent: React.FC = () => {
const [isDirty, setIsDirty] = useState(false);
// Задавайте нужное сообщение
usePrompt('У вас есть несохраненные изменения. Вы действительно хотите покинуть страницу?', isDirty);
const handleSave = () => {
// Логика сохранения изменений
setIsDirty(false);
};
// Логика изменения состояния, когда пользователь вводит данные
const handleInputChange = () => {
setIsDirty(true);
};
return (
<div>
<input type="text" onChange={handleInputChange} />
<button onClick={handleSave}>Сохранить</button>
</div>
);
};
export default MyComponent;
Объяснение работы кода
-
Создание пользовательского хука (
usePrompt
): Этот хук инициирует слушатель для событияbeforeunload
, оно срабатывает при попытке закрыть или перезагрузить страницу. Также добавляется обработчик событий для обработки переходов внутри приложения. -
Обработка навигации: Когда пользователь пытается уйти со страницы, если
isDirty
(состояние, указывающее на наличие несохраненных изменений) истинно, будет показано сообщение с подтверждением. -
Использование в компоненте: В вашем компоненте нужно отслеживать состояние очищаемых данных и вызывать
usePrompt
, передавая текст сообщения и состояние.
Заключение
Таким образом, с помощью вышеописанных шагов и кода вы сможете контролировать навигацию пользователя в вашем приложении, защищая от случайной потери несохраненных данных. Если у вас возникнут вопросы или трудности при имплементации, не стесняйтесь спрашивать.