Skip to content

Not working with React Router v6 beta #3

@quarklemotion

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

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