Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to capture pop event in react-router-dom v6

I’m able to capture push event and control the navigation if my page has unsaved changes (isDirty: true) in react-router-dom v6 whereas I’m not able to wrap my head for pop event. Seems navigator from NavigationContext doesnt have pop event exposed directly to use. Can anyone help?

My Code for push event looks like this –

import {useEffect} from 'react';
import {UNSAFE_NavigationContext as NavigationContext} from 'react-router-dom';


function useConfirmExit(confirmExit: () => Promise<boolean>, when = true): void {
    const {navigator} = useContext(NavigationContext);

    useEffect(() => {
        if (!when) {
            return () => { };
        }

        const push = navigator.push;

        navigator.push = async (...args: Parameters<typeof push>) => {
            const result = await confirmExit();
            if (result !== false) {
                console.log('Save to be invoked');
                push(...args);
            }
        };
        
        return () => {
            navigator.push = push;
        };
    }, [navigator, confirmExit, when]);
}

confirmExit is just another async function which is taking input of user if he wants to navigate away from the unsaved page.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

The navigator doesn’t have any of the navigation actions, e.g. PUSH, POP, REPLACE, but it does have the go function to move forward/backward through the history stack. navigator.go(-1) is synonymous to a goBack or back navigation.

/**
 * A Navigator is a "location changer"; it's how you get to different locations.
 *
 * Every history instance conforms to the Navigator interface, but the
 * distinction is useful primarily when it comes to the low-level <Router> API
 * where both the location and a navigator must be provided separately in order
 * to avoid "tearing" that may occur in a suspense-enabled app if the action
 * and/or location were to be read directly from the history instance.
 */
export interface Navigator {
  createHref: History["createHref"];
  // Optional for backwards-compat with Router/HistoryRouter usage (edge case)
  encodeLocation?: History["encodeLocation"];
  go: History["go"];
  push(to: To, state?: any, opts?: NavigateOptions): void;
  replace(to: To, state?: any, opts?: NavigateOptions): void;
}

You could augment the go function as well, something like the following:

import { useEffect } from 'react';
import { UNSAFE_NavigationContext as NavigationContext } from 'react-router-dom';

function useConfirmExit(confirmExit: () => Promise<boolean>, when = true): void {
  const { navigator } = useContext(NavigationContext);

  useEffect(() => {
    if (!when) {
      return () => { };
    }

    const { go, push } = navigator;

    navigator.go = async (delta: number) => {
      const result = await confirmExit();
      if (result !== false) {
        console.log('Save to be invoked');
        go(delta);
      }
    };

    navigator.push = async (...args: Parameters<typeof push>) => {
      const result = await confirmExit();
      if (result !== false) {
        console.log('Save to be invoked');
        push(...args);
      }
    };
        
    return () => {
      navigator.go = go;
      navigator.push = push;
    };
  }, [navigator, confirmExit, when]);
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading