React-router: Is there any event/hook to detect route change?

Created on 20 Jun 2016  路  15Comments  路  Source: ReactTraining/react-router

I have a <Router> with many <Route>

I want count each page views like Google Analytics

So the problem is how to detect Router url changing ?

Most helpful comment

@EasonWang01 It will after you hit Enter

All 15 comments

Can't you use onChange or onEnter property? Just add that you your top level route(s) and it will call a function and pass you the information about the previous and the next route.

 <Route path="/" onChange={yourHandler} component={AppContainer}>
   <IndexRoute component={StaticContainer}  />
   <Route path="/a" component={ContainerA}  />
   <Route path="/b" component={ContainerB}  />
 </Route>

function yourHandler(previousRoute, nextRoute) {
   //do your logic here
}

Edit:

For this specific case maybe using the hooks on the router it's a bit of an overkill. You can also add an event listener to your browser history if you use one.

import { browserHistory } from 'react-router';

//Your initialization

browserHistory.listen( location =>  {
 //Do your stuff here
});

browserHistory.listen won't work if you type url in address bar.

@EasonWang01 It will after you hit Enter

I agree with @EasonWang01, I had tried using browserHistory.listen and it was't called after I typed url.

In a redux app, I've been using syncHistoryWithStore from react router redux. The example below works after typing url in address bar:

const history = syncHistoryWithStore(browserHistory, store)

history.listen(location => analyticsService.track(location.pathname))

Source: https://github.com/reactjs/react-router-redux

When you're loading up a page for the first time (i.e., when you type in a URL in the browser), under history 3.x, the first listen doesn't immediately fire back. You should get the location initially with getCurrentLocation instead.

I'm using react router dom.
After importing: let Router = require('react-router-dom').BrowserRouter; Should I import import { browserHistory } from 'react-router';?

No, this library doesn't work with React Router or history 4.0. Please see the top of the README.

How do you listen for route changes with React Router 4.0?

Get history off context or create it outside the Router and pass it in as a history prop.

For React-Router 4 I solved this by wrapping one of my top level components using the HOC withRouter. This allows me to access this.props.history. The component is a parent element of every other component in the app. In code...

//index.js
ReactDOM.render(
    <Provider store={store}>
      <BrowserRouter>
            <AppContainer>
                   <Route exact path="/" Component={...} />
                   <Route exact path="/Home" Component={...} />
           </AppContainer>
        </BrowserRouter>
    </Provider>,
  document.getElementById('root')
);

//AppContainer.js
import App from '../components/App';
import { connect } from 'react-redux';
import { withRouter } from 'react-router'

function mapStateToProps(state) {
  return {};
}

function mapDispatchToProps() {
    return {};
}

export default withRouter(connect(mapStateToProps, mapDispatchToProps)(App));

//App.js
class App extends Component {
  constructor(props) {
    super(props);

   //Here ya go
    this.props.history.listen((location, action) => {
      console.log("on route change");
    });
  }

  render() {
     return (
         {this.props.children}
      );
  }
}

@roblapp This way can be listen route change. But easy duplicate listens, how to listen only once?

@lizhong8532 From testing, history.listen() returns an unlisten function. You'd use this to unregister from listening.
Example:

this.unlisten = this.props.history.listen(...);
//Later...
this.unlisten();

Presumably, one could attach a listener in componentDidMount and unlisten in componentWillUnmount or similar...

@amxfonseca I want to do something just before the route change in url. Currently onEnter and browserHistory.listen are fired just immediately after url change. I want something like onEnterBefore. Is there any way around?

@vnsrahul1304 I'm not that familiar with the router. But I think there are some possible solutions:

You can use the onLeave hook from the router, but I think you can't run anything asynchronous there so it may not be suited for your specific use case.

And if I'm not mistaken you also have the listenBefore event on the history. This one provides you with a callback that you can call when you're ready to proceed. It may create a sluggish navigation experience though

history.listenBefore( (location, done) => doSomething(location).then(done) )

In last case scenario you can always wrap the Link component provided by React Router and add your own custom logic there.

@amxfonseca Thanks a lot! history.listenBefore works great for me. And I am also able to get the current route(through window.location.pathname) as well as the next route through the location param of listenBefore. Also the navigation seems fine.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ackvf picture ackvf  路  3Comments

maier-stefan picture maier-stefan  路  3Comments

misterwilliam picture misterwilliam  路  3Comments

ryansobol picture ryansobol  路  3Comments

yormi picture yormi  路  3Comments