How to listen to route changes in react router v4?

I use withRouter to get the location prop. When the component is updated because of a new route, I check if the value changed:

@withRouter
class App extends React.Component {

  static propTypes = {
    location: React.PropTypes.object.isRequired
  }

  // ...

  componentDidUpdate(prevProps) {
    if (this.props.location !== prevProps.location) {
      this.onRouteChanged();
    }
  }

  onRouteChanged() {
    console.log("ROUTE CHANGED");
  }

  // ...
  render(){
    return <Switch>
        <Route path="/" exact component={HomePage} />
        <Route path="/checkout" component={CheckoutPage} />
        <Route path="/success" component={SuccessPage} />
        // ...
        <Route component={NotFound} />
      </Switch>
  }
}

Hope it helps


To expand on the above, you will need to get at the history object. If you are using BrowserRouter, you can import withRouter and wrap your component with a higher-order component (HoC) in order to have access via props to the history object's properties and functions.

    import { withRouter } from 'react-router-dom';

    const myComponent = ({ history }) => {

        history.listen((location, action) => {
            // location is an object like window.location
            console.log(action, location.pathname, location.state)
        });

        return <div>...</div>;
    };

    export default withRouter(myComponent);

The only thing to be aware of is that withRouter and most other ways to access the history seem to pollute the props as they de-structure the object into it.

As others have said, this has been superseded by the hooks exposed by react router and it has a memory leak. If you are registering listeners in a functional component you should be doing so via useEffect and unregistering them in the return of that function.


v5.1 introduces the useful hook useLocation

https://reacttraining.com/blog/react-router-v5-1/#uselocation

import { Switch, useLocation } from 'react-router-dom'

function usePageViews() {
  let location = useLocation()

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

function App() {
  usePageViews()
  return <Switch>{/* your routes here */}</Switch>
}

You should to use history v4 lib.

Example from there

history.listen((location, action) => {
  console.log(`The current URL is ${location.pathname}${location.search}${location.hash}`)
  console.log(`The last navigation action was ${action}`)
})

withRouter, history.listen, and useEffect (React Hooks) works quite nicely together:

import React, { useEffect } from 'react'
import { withRouter } from 'react-router-dom'

const Component = ({ history }) => {
    useEffect(() => history.listen(() => {
        // do something on route change
        // for my example, close a drawer
    }), [])

    //...
}

export default withRouter(Component)

The listener callback will fire any time a route is changed, and the return for history.listen is a shutdown handler that plays nicely with useEffect.