Last active
November 13, 2024 16:02
-
-
Save rmorse/426ffcc579922a82749934826fa9f743 to your computer and use it in GitHub Desktop.
Adds back in `useBlocker` and `usePrompt` to `react-router-dom` version 6.0.2 (they removed after the 6.0.0 beta, temporarily)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* These hooks re-implement the now removed useBlocker and usePrompt hooks in 'react-router-dom'. | |
* Thanks for the idea @piecyk https://github.com/remix-run/react-router/issues/8139#issuecomment-953816315 | |
* Source: https://github.com/remix-run/react-router/commit/256cad70d3fd4500b1abcfea66f3ee622fb90874#diff-b60f1a2d4276b2a605c05e19816634111de2e8a4186fe9dd7de8e344b65ed4d3L344-L381 | |
*/ | |
import { useContext, useEffect, useCallback } from 'react'; | |
import { UNSAFE_NavigationContext as NavigationContext } from 'react-router-dom'; | |
/** | |
* Blocks all navigation attempts. This is useful for preventing the page from | |
* changing until some condition is met, like saving form data. | |
* | |
* @param blocker | |
* @param when | |
* @see https://reactrouter.com/api/useBlocker | |
*/ | |
export function useBlocker( blocker, when = true ) { | |
const { navigator } = useContext( NavigationContext ); | |
useEffect( () => { | |
if ( ! when ) return; | |
const unblock = navigator.block( ( tx ) => { | |
const autoUnblockingTx = { | |
...tx, | |
retry() { | |
// Automatically unblock the transition so it can play all the way | |
// through before retrying it. TODO: Figure out how to re-enable | |
// this block if the transition is cancelled for some reason. | |
unblock(); | |
tx.retry(); | |
}, | |
}; | |
blocker( autoUnblockingTx ); | |
} ); | |
return unblock; | |
}, [ navigator, blocker, when ] ); | |
} | |
/** | |
* Prompts the user with an Alert before they leave the current screen. | |
* | |
* @param message | |
* @param when | |
*/ | |
export function usePrompt( message, when = true ) { | |
const blocker = useCallback( | |
( tx ) => { | |
// eslint-disable-next-line no-alert | |
if ( window.confirm( message ) ) tx.retry(); | |
}, | |
[ message ] | |
); | |
useBlocker( blocker, when ); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const MyComponent = () => { | |
const formIsDirty = true; // Condition to trigger the prompt. | |
usePrompt( 'Leave screen?', formIsDirty ); | |
return ( | |
<div>Hello world</div> | |
); | |
}; |
you can simply add these:
useEffect(() => {
window.addEventListener("beforeunload", onBeforeUnload);
return () => {
window.removeEventListener("beforeunload", onBeforeUnload);
};
});
const onBeforeUnload = (e) => {
if (hasDirty) {
e.preventDefault();
e.returnValue = "";
}
};
Reference : https://claritydev.net/blog/display-warning-for-unsaved-form-data-on-page-exit
you can simply add these:
useEffect(() => { window.addEventListener("beforeunload", onBeforeUnload); return () => { window.removeEventListener("beforeunload", onBeforeUnload); }; }); const onBeforeUnload = (e) => { if (hasDirty) { e.preventDefault(); e.returnValue = ""; } };
Reference : https://claritydev.net/blog/display-warning-for-unsaved-form-data-on-page-exit
This doesn't fire during route transitions...
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is awesome, thanks for sharing! 💯