6

I want to popup a modal if a use leaves a form page that tells them their changes will be lost if they leave and they have the option to leave or cancel.

I saw that recent changes to V6 from beta takes out the use of Prompt, useBlocker, and useHistory. I have seen answers for using onBeforeUnload but that seems to only use a built in prompt.

Is there a way to do this with the useNavigate hook?

Kasie Chaplick
  • 91
  • 1
  • 1
  • 5

2 Answers2

5

Here's a similar issue on GitHub https://github.com/remix-run/react-router/issues/8139.

A possible solution is using UNSAFE_NavigationContext if it exposes block option. See https://github.com/remix-run/react-router/issues/8139#issuecomment-977790637.

I tested it with "react-router-dom": "^6.0.2" and it works [as a workaround] for now.

Agon Qorolli
  • 51
  • 1
  • 3
1

An alternative solution is to implement a custom router like suggested here: react router v6 navigate outside of components

The implementation of the Router is pretty simple, and once you have it setup you can put your history object in a React Context or your state management solution and call history.block when you want to trigger the prompt.

Something like this:

  const { history } = useNavigationContext();

  // This ref is used to save the destination location to which we plan to navigate after the dirty check is complete
  const navigateDestination = useRef<Transition>();

  const onConfirmLeave = () => {
     navigateDestination.current?.retry();
  };

  const unblockNavigationRef = useRef<Function>();

  useEffect(() => {
    if (isDirty) {
      // Remove previous block function if exists.
      unblockNavigationRef.current?.();

      // Block route navigation requests when the isDirty flag is on.
      // Instead of navigating when an attempt to navigate happens, save the destination route and render the dirty prompt
      unblockNavigationRef.current = history.block((transition: Transition) => {
        navigateDestination.current = transition;
        renderPrompt(onConfirmLeave);
      });
    } else {
      // Unblock navigation when the dirty state is cleared
      unblockNavigationRef.current?.();
    }
  }, [isDirty, history]);
Yael
  • 183
  • 1
  • 1
  • 11