Search code examples
reactjsreact-routerreact-router-dom

React Router v.6 usePrompt TypeScript


I am basically trying to intercept route changes. Maybe something equivalent of vue's beforeEach in React Router v6 could be useful as React Router v.6 does not include usePrompt.

BEFORE each route change I want to do some logic - the logic might need to interrupt or even change the end route based on the result.

I have searched around but I really can't find something that solves this specific problem.

Thanks in advance.


Solution

  • Currently they have removed the usePrompt from the react-router v6.

    I found a solution from ui.dev and added TypeScript support, and am now using that until the react-router will bring back the usePrompt/useBlocker hooks

    import { History, Transition } from 'history';
    import { useCallback, useContext, useEffect } from "react";
    import { Navigator } from 'react-router';
    import { UNSAFE_NavigationContext as NavigationContext } from "react-router-dom";
    
    type ExtendNavigator = Navigator & Pick<History, "block">;
    export function useBlocker(blocker: (tx: Transition) => void, when = true) {
        const { navigator } = useContext(NavigationContext);
    
        useEffect(() => {
            if (!when) return;
    
            const unblock = (navigator as ExtendNavigator).block((tx) => {
                const autoUnblockingTx = {
                    ...tx,
                    retry() {
                        unblock();
                        tx.retry();
                    },
                };
    
                blocker(autoUnblockingTx);
            });
    
            return unblock;
        }, [navigator, blocker, when]);
    }
    
    export default function usePrompt(message: string, when = true) {
        const blocker = useCallback((tx: Transition) => {
            if (window.confirm(message)) tx.retry();
        }, [message]);
    
        useBlocker(blocker, when);
    }
    

    This can then be used in any view/component where you would like a "A you sure you want to leave?"-message displayed when the condition is true.

    usePrompt("Do you want to leave?", isFormDirty());