Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to controling browser back button with react router dom v6?

I've been looking for this question and found it but they're using class components and react router dom v5

What i want is When user click browser back button I'll redirect them to home page

like image 227
Esa Kurniawan Avatar asked Nov 21 '25 03:11

Esa Kurniawan


2 Answers

Well after a long journey to find out how to do that finally i came up with this solution

window.onpopstate = () => {
  navigate("/");
}
like image 163
Esa Kurniawan Avatar answered Nov 22 '25 18:11

Esa Kurniawan


React-Router-Dom v6.0+ Routers

If you are simply wanting to run a function when a back navigation (POP action) occurs then a possible solution is to create a custom hook for it using the exported NavigationContext.

Example:

import { UNSAFE_NavigationContext } from "react-router-dom";

const useBackListener = (callback) => {
  const navigator = useContext(UNSAFE_NavigationContext).navigator;

  useEffect(() => {
    const listener = ({ location, action }) => {
      console.log("listener", { location, action });
      if (action === "POP") {
        callback({ location, action });
      }
    };

    const unlisten = navigator.listen(listener);
    return unlisten;
  }, [callback, navigator]);
};

Usage:

import { useNavigate } from 'react-router-dom';
import { useBackListener } from '../path/to/useBackListener';

...

const navigate = useNavigate();

useBackListener(({ location }) => {
  console.log("Navigated Back", { location });
  navigate("/", { replace: true });
});

If using the UNSAFE_NavigationContext context is something you'd prefer to avoid then the alternative is to create a custom route that can use a custom history object (i.e. from createBrowserHistory) and use the normal history.listen. See my answer here for details.

w/ Typescript

import { useEffect, useContext } from "react";
import { NavigationType, UNSAFE_NavigationContext } from "react-router-dom";
import { History, Update } from "history";

const useBackListener = (callback: (...args: any) => void) => {
  const navigator = useContext(UNSAFE_NavigationContext).navigator as History;

  useEffect(() => {
    const listener = ({ location, action }: Update) => {
      console.log("listener", { location, action });
      if (action === NavigationType.Pop) {
        callback({ location, action });
      }
    };

    const unlisten = navigator.listen(listener);
    return unlisten;
  }, [callback, navigator]);
};

You can also use the useNavigationType hook if all you want is to know if a POP action occurred.

import {
  useLocation,
  useNavigationType,
  NavigationType
} from "react-router-dom";

const useBackListener = (callback) => {
  // Ref is used to handle any React.StrictMode double-mounting
  const initialRender = React.useRef(true);

  const location = useLocation();
  const navigationType = useNavigationType();

  useEffect(() => {
    if (!initialRender.current && navigationType === NavigationType.Pop) {
      initialRender.current = false;
      callback({ location });
    }

  }, [callback, location, navigationType]);
};

React-Router-Dom v6.4+ Data Routers

With the Data routers you can use the (currently still used) router.subscribe handler to replace history.listen. It is easily also abstracted into a custom if necessary. Note that subscribe is not currently part of the "public" API and exists similar to NavigationContext and HistoryRouter where they could be removed at any time. See this Github issue for more details/explanation.

Example:

const router = createBrowserRouter([
  ...
]);

export default function App() {
  React.useEffect(() => {
    router.subscribe((state) => {
      if (state.historyAction === NavigationType.Pop) {
        ....
      }
    });
  }, []);

  return <RouterProvider router={router} />;
}

Example state value:

{
  actionData: null,
  blockers: {size: 0},
  errors: null,
  fetchers: {size: 0},
  historyAction: "PUSH",
  initialized: true,
  loaderData: {},
  location: {
    pathname: '/1',
    search: '',
    hash: '',
    state: null,
    key: 'oy0tkdth'
  },
  matches: [{…}, {…}],
  navigation: {
    state: 'idle',
    location: undefined,
    formMethod: undefined,
    formAction: undefined,
    formEncType: undefined,
    …
  },
  preventScrollReset: false,
  restoreScrollPosition: null,
  revalidation: "idle"
}
like image 30
Drew Reese Avatar answered Nov 22 '25 19: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!