我正在尝试实现一个确认模式,当用户尝试导航离开未保存更改的页面时会出现该模式。当单击浏览器的后退按钮或页面上的“上一个”按钮时,模式会正确显示,但是当我确认操作时,模式会进入无限循环,不断再次打开而不是导航离开。此问题仅出现在后退按钮或“上一页”按钮上;通过其他链接导航时,一切都按预期进行。
当点击触发导航到特定路径(例如,从标题链接)的链接或按钮时,模式工作正常,但当确认由浏览器的后退按钮或浏览器中的“上一个”按钮触发的导航时,模式会进入无限循环。形式。
如果没有 window.history.pushState(null, '', location.pathname + location.search);,模态框根本不会出现在后退导航上,但是有了它,模态框在尝试时会不断地在无限循环中重新出现。确认返回导航。
如何防止模态进入无限循环并在用户确认后退导航时正确导航离开?
`const EstimateRequestPage = () => {
const navigate = useNavigate();
const location = useLocation();
const params = new URLSearchParams(location.search);
const [isModalOpen, setIsModalOpen] = useState(false);
const { isDirty, setIsDirty } = useIsDirty();
const { handleNavigate, renderModal } = usePreventLeave(isDirty);
return (
<Container>
<form onSubmit={handleSubmit}>
{/* Form fields... */}
<ButtonGroup>
<PreviousButton variant="outlined" onClick={() => handleNavigate(-1)}>
Previous
</PreviousButton>
<RequestButton variant="contained" type="submit">
Submit
</RequestButton>
</ButtonGroup>
</form>
{renderModal()}
</Container>
);
};`
`import { useState, useCallback, useEffect } from 'react';
import { useLocation, useNavigate } from 'react-router-dom';
import ConfirmationModal from '@/components/ui/modal/Modal';
export const usePreventLeave = (isDirty) => {
const [isModalOpen, setIsModalOpen] = useState(false);
const [pendingPath, setPendingPath] = useState(null);
const navigate = useNavigate();
const location = useLocation();
useEffect(() => {
const handlePopState = (event) => {
if (isDirty) {
window.history.pushState(null, '', location.pathname + location.search);
setIsModalOpen(true);
}
};
window.history.pushState(null, '', location.pathname + location.search);
window.addEventListener('popstate', handlePopState);
return () => {
window.removeEventListener('popstate', handlePopState);
};
}, [isDirty, location.pathname, location.search]);
const handleNavigate = useCallback(
(path) => {
if (isDirty) {
setPendingPath(path);
setIsModalOpen(true); // Show modal
} else {
navigate(path); // Navigate if not dirty
}
},
[isDirty, navigate]
);
const handleConfirm = useCallback(() => {
setIsModalOpen(false);
if (pendingPath === null) {
navigate(-1); // Back navigation
} else if (pendingPath) {
navigate(pendingPath); // Navigate to pending path
}
setPendingPath(null);
}, [navigate, pendingPath]);
const handleCancel = useCallback(() => {
setIsModalOpen(false);
setPendingPath(null); // Reset state
}, []);
return {
handleNavigate,
renderModal: () => (
<ConfirmationModal
open={isModalOpen}
handleClose={handleCancel}
handleConfirm={handleConfirm}
messageId1="Leave page?"
messageId2="Unsaved changes will be lost."
confirmButtonId="confirm_button"
/>
),
setPendingPath,
};
};
`
问题是,当您确认导航时,handleNavigate函数可能会触发状态更改,导致handlePopState再次运行,从而导致无限循环。尝试下面的代码,我提供了使用 event.preventDefault() 代替 window.history.pushState() ,并在组件卸载后添加事件侦听器并删除事件侦听器,并从 useeffect 依赖项数组中删除 location.pathname 和 location.search 。
useEffect(() => {
const handlePopState = (event) => {
if (isDirty) {
// Prevent the default behavior and show the modal
event.preventDefault();
setIsModalOpen(true);
}
};
// Adding event listener for popstate
window.addEventListener('popstate', handlePopState);
// Clean up the event listener on component unmount
return () => {
window.removeEventListener('popstate', handlePopState);
};
}, [isDirty]);