/** * 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: any, when = true) { const { navigator } = useContext(NavigationContext); useEffect(() => { if (!when) return; const unblock = (navigator as any).block((tx: any) => { 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: string, when = true) { const blocker = useCallback( (tx: any) => { // eslint-disable-next-line no-alert if (window.confirm(message)) tx.retry(); }, [message] ); useBlocker(blocker, when); }