/** * 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 default 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 ); }