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 ?
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))
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.
Most helpful comment
@EasonWang01 It will after you hit Enter