'how to listen for route change in react-router-dom v6

am trying to migrate the old react router dom code to v6 and I want to know how to listen for route change, I am now using useHistory

const history = useHistory()
//then
history.listen(...)

I did read the new docs and I did find that useHistory was changed to useNavigate

const navigate = useNavigate()
//then
navigate.listen(...) // listen is not a function

can you please help me find a way to listen to the route change in v6

// This is a React Router v6 app
import { useNavigate } from "react-router-dom";

function App() {
  let navigate = useNavigate();
  function handleClick() {
    navigate("/home");
  }
  return (
    <div>
      <button onClick={handleClick}>go home</button>
    </div>
  );
}


Solution 1:[1]

The navigate function is a function, not an object like the older react-router-dom version 5's history object.

You can still create a custom history object but you'll need to create a custom router to use it. This allows you to import your history object and create listeners.

Create a custom router example, use one of the higher-level routers as an example for how they manage the location and state, i.e. BrowserRouter:

const CustomRouter = ({ history, ...props }) => {
  const [state, setState] = useState({
    action: history.action,
    location: history.location
  });

  useLayoutEffect(() => history.listen(setState), [history]);

  return (
    <Router
      {...props}
      location={state.location}
      navigationType={state.action}
      navigator={history}
    />
  );
};

In your code create the custom history object for use by your new custom router and other components.

const history = createBrowserHistory();
export default history;

Use your router and pass your history object to it.

import CustomRouter from '../CustomRouter';
import history from '../myHistory';

...

<CustomRouter history={history}>
  ....
</CustomRouter>

In a component you want to listen to location changes on, import your history object and invoke the listen callback as you did previously.

import history from '../myHistory';

...

useEffect(() => {
  const unlisten = history.listen((location, action) => {
    // ... logic
  });

  return unlisten;
}, []);

If you want, you may be able to also create your own custom useHistory hook that simply returns your history object.

Solution 2:[2]

To add to the accepted answer (can't comment, not enough rep points), subscribing to the history through a useEffect with location.pathname in the dependency array won't work if the navigation unmounts the component you're attempting to call the useEffect from.

Solution 3:[3]

From documentation (https://reactrouter.com/docs/en/v6/hooks/use-location), use this hook

let location = useLocation();

React.useEffect(() => {
  ga('send', 'pageview');
}, [location]);

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Drew Reese
Solution 2 hiroshin
Solution 3 José Lozano Hernández