Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to show confirmation message before leaving the screen in react-router-dom V6?

I need to add a new feature to my work project, when the user wants to leave the page, a confirmation message should appear that they really want to do.

I found a working example but it is in react-router-dom@5. In the project of the company I work for, they use react-router-dom@6. I tried to adapt it but it didn't work, mainly because of the block() method.

Here's my adapted code I put into codesandbox

import React, { useState, useCallback, useEffect } from "react";
import { Link, useNavigate } from "react-router-dom";
import ExitDialog from "./ExitDialog";

const TestingPage = () => {
  const navigate = useNavigate();
  const [isVisibleDialog, setVisibleDialog] = useState(false);
  const [triggerExit, setTriggerExit] = useState({
    onOk: false,
    path: ""
  });

  const handleGoToIntendedPage = useCallback(
    (location) => navigate(location),
    [navigate]
  );

  useEffect(() => {
    if (triggerExit.onOk) {
      handleGoToIntendedPage(triggerExit.path);
    }

    const unblock = navigate.block((location) => {
      if (location.pathname !== "/testing") {
        setVisibleDialog(true);
      }
      setTriggerExit((obj) => ({ ...obj, path: location.pathname }));
      if (triggerExit.onOk) {
        return true;
      }
      return false;
    });

    return () => {
      unblock();
    };
  }, [handleGoToIntendedPage, navigate, triggerExit.onOk, triggerExit.path]);

  return (
    <div>
      <div>
        <h1>You are currently in Testing Page</h1>
      </div>
      <div>
        <Link to="/">Home</Link>
      </div>
      <ExitDialog
        visible={isVisibleDialog}
        onClose={() => setVisibleDialog(false)}
        onOk={() => {
          setTriggerExit((obj) => ({
            ...obj,
            onOk: true
          }));
          setVisibleDialog(false);
        }}
      />
    </div>
  );
};

export default TestingPage;

This is the example that is working with react-router-dom@5

enter image description here

Can you tell me how to fix this?

like image 964
Katyellen Avatar asked Nov 28 '25 14:11

Katyellen


1 Answers

For what it's worth, in the [email protected] version used in the sandbox you linked the following method still works.

  1. Create and use a HistoryRouter router and custom history object. This requires the history package as a project dependency.

    1. Add history as a project dependency: npm install --save history@5.

    2. Create the custom history object.

      /src/history.js

      import { createBrowserHistory } from 'history';
      
      export default createBrowserHistory();
      
    3. Import the HistoryRouter and your custom history object, instantiate the router.

      import { createRoot } from "react-dom/client";
      import {
        unstable_HistoryRouter as Router // <-- HistoryRouter
      } from "react-router-dom";
      import history from './history';   // <-- custom history object
      import App from "./App";
      
      const rootElement = document.getElementById("root");
      const root = createRoot(rootElement);
      
      root.render(
        <Router history={history}> // <-- render HistoryRouter
          <App />
        </Router>
      );
      
  2. Update TestingPage to import and use the custom history object. Note that history.block callback takes a single argument where location is just one of the properties.

    import React, { useState, useCallback, useEffect } from "react";
    import { useNavigate } from "react-router-dom";
    import ExitDialog from "./ExitDialog";
    import history from '../history';
    
    const TestingPage = () => {
      const navigate = useNavigate();
    
      const [isVisibleDialog, setVisibleDialog] = useState(false);
      const [triggerExit, setTriggerExit] = useState({
        onOk: false,
        path: ""
      });
    
      const handleGoToIntendedPage = useCallback((location) => navigate(location), [
        navigate
      ]);
    
      useEffect(() => {
        if (triggerExit.onOk) {
          handleGoToIntendedPage(triggerExit.path);
        }
    
        const unblock = history.block(({ location }) => { // <-- block callback
          if (location.pathname !== "/testing") {
            setVisibleDialog(true);
          }
          setTriggerExit((obj) => ({ ...obj, path: location.pathname }));
          if (triggerExit.onOk) {
            return true;
          }
          return false;
        });
    
        return () => {
          unblock();
        };
      }, [handleGoToIntendedPage, navigate, triggerExit.onOk, triggerExit.path]);
    
      return (
        <div>
          <div>
            <h1>You are currently in Testing Page</h1>
          </div>
          <ExitDialog
            visible={isVisibleDialog}
            onClose={() => setVisibleDialog(false)}
            onOk={() => {
              setTriggerExit((obj) => ({
                ...obj,
                onOk: true
              }));
              setVisibleDialog(false);
            }}
          />
        </div>
      );
    };
    
    export default TestingPage;
    

Edit how-to-show-confirmation-message-before-leaving-the-screen-in-react-router-dom-v

The HistoryRouter is renamed (and marked "unstable") which means it could be removed at any time, but it's been included with each minor release including the current stable release (v6.15.0 as of this posting).

HistoryRouter Source

like image 71
Drew Reese Avatar answered Nov 30 '25 04:11

Drew Reese



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!