Skip to content

Not working with React Router v6 beta #3

Description

@quarklemotion

Just logging an issue to note that react-router-pause does not work with the new beta of react router v6. This is due to the removal of the withRouter HOC, which was replaced with several hooks including useNavigate and useBlocker.

Here is a working solution of a hook (in TypeScript) that integrates properly with react router v6 beta to provide a custom prompt when navigating away from a protected route:

import { useState, useEffect, useCallback } from 'react';
import { useBlocker, useNavigate, useLocation } from 'react-router-dom';
import { Blocker } from 'history';

export function useNavigationWarning(
  when: boolean,
  exceptPathsMatching?: RegExp
) {
  const navigate = useNavigate();
  const location = useLocation();
  const [showPrompt, setShowPrompt] = useState<boolean>(false);
  const [lastLocation, setLastLocation] = useState<any>(null);
  const [confirmedNavigation, setConfirmedNavigation] = useState<boolean>(
    false
  );

  const cancelNavigation = useCallback(() => {
    setShowPrompt(false);
  }, []);

  const handleBlockedNavigation = useCallback<Blocker>(
    nextLocation => {
      const shouldIgnorePathChange = exceptPathsMatching?.test(
        nextLocation.location.pathname
      );
      if (
        !(confirmedNavigation || shouldIgnorePathChange) &&
        nextLocation.location.pathname !== location.pathname
      ) {
        setShowPrompt(true);
        setLastLocation(nextLocation);
      } else if (shouldIgnorePathChange) {
        // to cancel blocking based on the route we need to retry the nextLocation
        nextLocation.retry();
      }
    },
    [confirmedNavigation, location.pathname, exceptPathsMatching]
  );

  const confirmNavigation = useCallback(() => {
    setShowPrompt(false);
    setConfirmedNavigation(true);
  }, []);

  useEffect(() => {
    if (confirmedNavigation && lastLocation?.location) {
      navigate(lastLocation.location.pathname);
    }
  }, [confirmedNavigation, lastLocation, navigate]);

  useBlocker(handleBlockedNavigation, when);

  return [showPrompt, confirmNavigation, cancelNavigation] as const;
}

credit: adapted from this codesandbox solution from this SO post

Activity

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

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingenhancementNew feature or request

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions