Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Adds back in `useBlocker` and `usePrompt` to `react-router-dom` version 6.0.2 (they removed after the 6.0.0 beta, temporarily)
/**
* 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 );
}
const MyComponent = () => {
const formIsDirty = true; // Condition to trigger the prompt.
usePrompt( 'Leave screen?', formIsDirty );
return (
<div>Hello world</div>
);
};
@mknospe
Copy link

mknospe commented Aug 4, 2022

Works like a charm. Thanks for sharing! 💯

@borstelmannl
Copy link

borstelmannl commented Sep 19, 2022

if i use this workaround: https://stackoverflow.com/a/71587163/8046487
i receive an exception: navigator.block is not a function. Anyone else having this issue?

i am using the newest react router version 6.4

@matrey
Copy link

matrey commented Sep 19, 2022

You can check the original github issue that led to the creation of this gist: remix-run/react-router#8139 (comment)

Just fyi, it's still possible to use navigator.block via history package with v6.4.0, by replacing BrowserRouter with unstable_HistoryRouter

@fcmdvtk4r
Copy link

fcmdvtk4r commented Sep 27, 2022

Resetting any of the dependencies at line 38 when canceling the navigation solved the TODO for me.

Thanks for sharing!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment