In Next How can i stop Router Navigation in Next JS.
I am trying to use routerChangeStart
event to stop navigation.
useEffect(() => {
const handleRouteChange = (url: string): boolean => {
if (dirty) {
return false;
}
return true;
};
Router.events.on('routeChangeStart', handleRouteChange);
return () => {
Router.events.off('routeChangeStart', handleRouteChange);
};
}, []);
It seems there is no perfect way to this but I handle it with this little trick:
React.useEffect(() => {
const confirmationMessage = 'Changes you made may not be saved.';
const beforeUnloadHandler = (e: BeforeUnloadEvent) => {
(e || window.event).returnValue = confirmationMessage;
return confirmationMessage; // Gecko + Webkit, Safari, Chrome etc.
};
const beforeRouteHandler = (url: string) => {
if (Router.pathname !== url && !confirm(confirmationMessage)) {
// to inform NProgress or something ...
Router.events.emit('routeChangeError');
// tslint:disable-next-line: no-string-throw
throw `Route change to "${url}" was aborted (this error can be safely ignored). See https://github.com/zeit/next.js/issues/2476.`;
}
};
if (notSaved) {
window.addEventListener('beforeunload', beforeUnloadHandler);
Router.events.on('routeChangeStart', beforeRouteHandler);
} else {
window.removeEventListener('beforeunload', beforeUnloadHandler);
Router.events.off('routeChangeStart', beforeRouteHandler);
}
return () => {
window.removeEventListener('beforeunload', beforeUnloadHandler);
Router.events.off('routeChangeStart', beforeRouteHandler);
};
}, [notSaved]);
This code will interrupt changing route (with nextJs Route and also browser refresh / close tab action)
You can write a custom hook.
import Router from 'next/router';
import { useEffect } from 'react';
const useWarnIfUnsavedChanges = (unsavedChanges, callback) => {
useEffect(() => {
const routeChangeStart = url => {
if (unsavedChanges) {
Router.events.emit('routeChangeError');
Router.replace(Router, Router.asPath, { shallow: true });
throw 'Abort route change. Please ignore this error.';
}
};
Router.events.on('routeChangeStart', routeChangeStart);
return () => {
Router.events.off('routeChangeStart', routeChangeStart);
};
}, [unsavedChanges]);
};
export default useWarnIfUnsavedChanges;
Take inspiration from: https://github.com/vercel/next.js/discussions/12348#discussioncomment-8089
Here's my custom hook solution that seems to cut it, written in TypeScript.
import Router from "next/router"
import { useEffect } from "react"
const useWarnIfUnsavedChanges = (unsavedChanges: boolean, callback: () => boolean) => {
useEffect(() => {
if (unsavedChanges) {
const routeChangeStart = () => {
const ok = callback()
if (!ok) {
Router.events.emit("routeChangeError")
throw "Abort route change. Please ignore this error."
}
}
Router.events.on("routeChangeStart", routeChangeStart)
return () => {
Router.events.off("routeChangeStart", routeChangeStart)
}
}
}, [unsavedChanges])
}
You can use it in your component as follows:
useWarnIfUnsavedChanges(changed, () => {
return confirm("Warning! You have unsaved changes.")
})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With