import SingletonRouter, { Router } from 'next/router';
import { useEffect } from 'react';
const defaultConfirmationDialog = async (msg?: string) => window.confirm(msg);
/**
* React Hook
*/
export const useLeavePageConfirmation = (
shouldPreventLeaving: boolean,
message: string = 'Changes you made may not be saved.',
confirmationDialog: (msg?: string) => Promise<boolean> = defaultConfirmationDialog
) => {
useEffect(() => {
// @ts-ignore because "change" is private in Next.js
if (!SingletonRouter.router?.change) {
return;
}
// @ts-ignore because "change" is private in Next.js
const originalChangeFunction = SingletonRouter.router.change;
const originalOnBeforeUnloadFunction = window.onbeforeunload;
/*
* Modifying the window.onbeforeunload event stops the browser tab/window from
* being closed or refreshed. Since it is not possible to alter the close or reload
* alert message, an empty string is passed to trigger the alert and avoid confusion
* about the option to modify the message.
*/
if (shouldPreventLeaving) {
window.onbeforeunload = () => '';
} else {
window.onbeforeunload = originalOnBeforeUnloadFunction;
}
/*
* Overriding the router.change function blocks Next.js route navigations
* and disables the browser's back and forward buttons. This opens up the
* possibility to use the window.confirm alert instead.
*/
if (shouldPreventLeaving) {
// @ts-ignore because "change" is private in Next.js
SingletonRouter.router.change = async (...args) => {
const [historyMethod, , as] = args;
// @ts-ignore because "state" is private in Next.js
const currentUrl = SingletonRouter.router?.state.asPath.split('?')[0];
const changedUrl = as.split('?')[0];
const hasNavigatedAwayFromPage = currentUrl !== changedUrl;
const wasBackOrForwardBrowserButtonClicked = historyMethod === 'replaceState';
let confirmed = false;
if (hasNavigatedAwayFromPage) {
confirmed = await confirmationDialog(message);
}
if (confirmed) {
// @ts-ignore because "change" is private in Next.js
Router.prototype.change.apply(SingletonRouter.router, args);
} else if (wasBackOrForwardBrowserButtonClicked && hasNavigatedAwayFromPage) {
/*
* The URL changes even if the user clicks "false" to navigate away from the page.
* It is necessary to update it to reflect the current URL.
*/
// @ts-ignore because "state" is private in Next.js
await SingletonRouter.router?.push(SingletonRouter.router?.state.asPath);
/*
* @todo
* I attempted to determine if the user clicked the forward or back button on the browser,
* but was unable to find a solution after several hours of effort. As a result, I temporarily
* hardcoded it to assume the back button was clicked, since that is the most common scenario.
* However, this may cause issues with the URL if the forward button is actually clicked.
* I hope that a solution can be found in the future.
*/
const browserDirection = 'back';
browserDirection === 'back'
? history.go(1) // back button
: history.go(-1); // forward button
}
};
}
/*
* When the component is unmounted, the original change function is assigned back.
*/
return () => {
// @ts-ignore because "change" is private in Next.js
SingletonRouter.router.change = originalChangeFunction;
window.onbeforeunload = originalOnBeforeUnloadFunction;
};
}, [shouldPreventLeaving, message, confirmationDialog]);
};
9条答案
按热度按时间tvmytwxo1#
我使用“next/router”,如NextJs Page来断开套接字
gudnpqoy2#
router.beforePopState
是伟大的浏览器后退按钮,但不是为<Link>
的网页上。解决方案在这里找到:https://github.com/vercel/next.js/issues/2694#issuecomment-732990201
...这里是一个版本的这种方法,对于任何人谁得到这个页面寻找另一种解决方案.注意,我已经适应了我的要求有点进一步.
到目前为止,它似乎工作得相当可靠。
或者,您可以自己将
onClick
添加到所有<Link>
中。r1zk6ea13#
您可以在此处使用
router.beforePopState
检查示例rt4zxlrg4#
我在写代码的时候看到了两件事:
我用这种方法做了一个钩子,如果使用下一个路由器,或者有一个经典的浏览器事件(关闭标签页,刷新),它就会触发
你只需要在你想要覆盖的组件中调用你的钩子:
这是我用useState创建的一个布尔值,在需要时进行编辑。这样,它只在需要时触发。
kiayqfof5#
您可以在react页面或组件中使用默认的web api's eventhandler。
ktca8awb6#
浏览器严重限制权限和功能,但这是有效的:
window.confirm
:用于next.js路由器事件beforeunload
:用于浏览器重新加载,关闭选项卡或导航离开此信用article
nuypyhwy7#
这在next-router / react-FC中对我有效
1.添加路由器事件处理程序
1.添加onBeforeUnload事件处理程序
1.卸载组件时卸载它们
https://github.com/vercel/next.js/issues/2476#issuecomment-563190607
hiz5n14c8#
我写了一篇中等的文章Prevent Route Changes and Unsaved Data Loss in Next.js。下面是完整的代码:
aydmsdu99#
您可以使用react-use npm package