How can I update a ReactJS component based on URL / path when using React-Router?
The code below works, but is this the correct way to do this? Seems like a lot of code
This question has been open awhile, and it seems like there should be a more straightforward solution, but I'll take a stab and share what we do in our application.
We are using the Flux architecture, which has the notion of Stores that inform components when their state is updated. In react-router
, they have a PathStore
that fits into this model nicely, since when the URL changes it can then notify components that care and need to be updated.
The StoreListener
we use in our application is publicly available here: https://github.com/odysseyscience/react-flux-suppprt. I should've published to NPM, but haven't yet. I'll do that soon if you think it would be helpful.
Here is how we use our StoreListener
to listen for changes on the PathStore
from react-router
, and how you would use it in your MyHeader
:
var StoreListener = require('path/to/StoreListener');
var PathStore = require ('react-router/modules/stores/PathStore');
var MyHeader = React.createClass({
mixins: [
StoreListener(PathStore)
],
getStateFromStores: function() {
return {
path: PathStore.getCurrentPath()
};
},
render: function() {
var path = this.state.path;
var myPath;
var classes;
if (this.state.path === "/") {
myPath = 'about';
classes = 'ion-ios7-information';
} else {
myPath = '/';
classes = 'ion-ios7-rewind';
}
return (
<Link to={myPath}>
<i className={classes} />
</Link>
);
}
});
This starts with a mixin
that says "I care about changes to the PathStore". Whenever this store (or any store being listened to) changes, getStateFromStores()
is called on your component in order to retrieve the data out of the store that you want available on this.state
. If/When that data changes, render()
is called again, and you re-read this.state
, and apply your changes.
This is exactly our pattern for applying certain "active" CSS classes on header tabs, or anywhere else in the application that depends on the current URL.
Note that we use webpack to bundle our CommonJS modules, so there may be some assumptions about the environment that may/may not work for you.
I didn't answer this question a month ago when I first saw it because I assumed there was a better way, but perhaps our solution can help others with the same issue.
In react-router 2.0.0 you can use the hashHistory or browserHistory:
browserHistory.listen(function(ev) {
console.log('listen', ev.pathname);
});
<Router history={browserHistory}>{routes}</Router>
This has been updated if you are working with the react-router > v11.0.
You can read the details here
TLDR:
// v0.11.x
var Something = React.createClass({
mixins: [ Router.State ],
render: function () {
var path = this.getPath();
}
});
For the full State
API: https://github.com/rackt/react-router/blob/master/doc/04%20Mixins/State.md