|
/* |
|
In standard web apps, when users navigate away to a different page or website or attempt to refresh a page, |
|
we can use the window event listener `beforeunload` to help users avoid losing the work. |
|
|
|
However, when a user clicks on a native NextJS <Link> component, the navigation is not intercepted |
|
because behind the scenes, no page changes are actually happening. |
|
To intercept user navigation in a NextJS app, we can subscribe to the |
|
router routeChangeError event and throw an error. |
|
Note: we must throw an Error string - not a `new Error()` - which is why in the code below, we have |
|
// eslint-disable-next-line no-throw-literal |
|
above the line throwing the error. |
|
*/ |
|
|
|
import Router from "next/router"; |
|
import { useEffect } from 'react'; |
|
|
|
const YourComponent = () => { |
|
|
|
// Relevent code begin |
|
const shouldBlockNavigation = true; // set this up however you want |
|
|
|
useEffect(() => { |
|
const nativeBrowserHandler = (event) => { |
|
if (shouldBlockNavigation) { |
|
event.preventDefault(); |
|
event.returnValue = ''; |
|
} |
|
}; |
|
|
|
const nextNavigationHandler = (url) => { |
|
if (shouldBlockNavigation) { |
|
if (!window.confirm('Navigate away? Changes you made may not be saved.')) { |
|
Router.events.emit('routeChangeError') |
|
// eslint-disable-next-line no-throw-literal |
|
throw "Abort route change by user's confirmation." |
|
} |
|
} |
|
}; |
|
|
|
window.addEventListener('beforeunload', nativeBrowserHandler); |
|
Router.events.on("beforeHistoryChange", nextNavigationHandler); |
|
|
|
// On component unmount, remove the event listener |
|
return () => { |
|
window.removeEventListener('beforeunload', nativeBrowserHandler); |
|
Router.events.off("beforeHistoryChange", nextNavigationHandler); |
|
}; |
|
}, [shouldBlockNavigation]); |
|
|
|
// Relevent code end |
|
|
|
return <div>Your Component</div> |
|
|
|
} |
So frickin' glad I came across this. This worked for me on Next 13.2.4.