自定义React路由器提示:历史记录一次只支持一个提示



我创建了一个自定义的React Router Prompt,用于显示用户何时想要导航到其他页面,但尚未保存数据。

一切似乎都在正常工作,但我有一个烦人的警告:

Warning: A history supports only one prompt at a time

组件如下所示:

export function RouterPrompt(props) {
const {when, onOK, onCancel, title} = props;
const history = useHistory();
const [showPrompt, setShowPrompt] = useState(false);
const [currentPath, setCurrentPath] = useState("");
useEffect(() => {
if (when) {
history.block((prompt) => {
setCurrentPath(prompt.pathname);
setShowPrompt(true);
return "true";
});
} else {
history.block(() => {
});
}
}, [when]);
const handleOK = useCallback(async () => {
if (onOK) {
const canRoute = await Promise.resolve(onOK());
if (canRoute) {
history.block(() => {
});
history.push(currentPath);
}
}
}, [currentPath, history, onOK]);
const handleCancel = useCallback(async () => {
if (onCancel) {
const canRoute = await Promise.resolve(onCancel());
if (canRoute) {
history.block(() => {
});
history.push(currentPath);
}
}
setShowPrompt(false);
}, [currentPath, history, onCancel]);
return showPrompt ? (
<Dialog
open={showPrompt}
onClose={handleCancel}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">
{title}
</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">
There are unsaved changes. Are you sure want to leave this page?
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={handleCancel}>Stay on page</Button>
<Button onClick={handleOK} autoFocus>
Leave
</Button>
</DialogActions>
</Dialog>
) : null;
}

据我所知,这来自于类生命周期方法(useEffect在卸载当前history.block之前运行(,但实际上DOM中只呈现了一个Prompt。

编辑

我发现了另一个错误,无论实际推送与否,这都会改变路径。因此,在URL中,路径会发生变化,但视图不会发生变化,所以下次当你按下后退键并确认时,你将在历史记录中后退两步。

我已经完全重组/重构了我的代码(原始代码来自一篇博客文章(,这似乎运行得很好(没有警告(,正如预期的那样:

export function RouterPrompt(props) {
const {when, title} = props;
const history = useHistory();
const [showPrompt, setShowPrompt] = useState(false);
const [currentPath, setCurrentPath] = useState("");
const unblockRef = useRef();
function handleShowModal() {
setShowPrompt(true);
}
function onCancel() {
setShowPrompt(false);
}
useEffect(() => {
unblockRef.current = history.block((location) => {
if (when) {
setCurrentPath(location.pathname);
handleShowModal();
return false;
}
return true;
});
return () => {
unblockRef.current && unblockRef.current();
};
}, [when]);
function handleConfirm() {
if (unblockRef) {
unblockRef.current();
}
setShowPrompt(false);
history.push(currentPath);
}
return (
<Dialog
open={showPrompt}
onClose={onCancel}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">
{title}
</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">
There are unsaved changes. Are you sure want to leave this page?
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={onCancel}>Stay on page</Button>
<Button onClick={handleConfirm} autoFocus>
Leave
</Button>
</DialogActions>
</Dialog>
);
}

最新更新