Here is the file that's causing me trouble:
var Routers = React.createClass({
getInitialState: function(){
return{
userName: "",
relatives: []
}
},
userLoggedIn: function(userName, relatives){
this.setState({
userName: userName,
relatives: relatives,
})
},
render: function() {
return (
<Router history={browserHistory}>
<Route path="/" userLoggedIn={this.userLoggedIn} component={LogIn}/>
<Route path="feed" relatives={this.state.relatives} userName={this.state.userName} component={Feed}/>
</Router>
);
}
});
I am trying to pass the new this.state.relatives and this.state.userName through the routes into my "feed"-component. But I'm getting this error message:
Warning: [react-router] You cannot change ; it will be ignored
I know why this happens, but don't know how else I'm supposed to pass the states to my "feed"-component.
tl;dr your best bet is to use a store like
reduxormobxwhen managing state that needs to be accessible throughout your application. Those libraries allow your components to connect to/observe the state and be kept up to date of any state changes.What is a
<Route>?The reason that you cannot pass props through
<Route>components is that they are not real components in the sense that they do not render anything. Instead, they are used to build a route configuration object.That means that this:
is equivalent to this:
The routes are only evaluated on the initial mount, which is why you cannot pass new props to them.
Static Props
If you have some static props that you want to pass to your store, you can create your own higher order component that will inject them into the store. Unfortunately, this only works for static props because, as stated above, the
<Route>s are only evaluated once.Using
location.statelocation.stateis a convenient way to pass state between components when you are navigating. It has one major downside, however, which is that the state only exists when navigating within your application. If a user follows a link to your website, there will be no state attached to the location.Using A Store
So how do you pass data to your route's
components? A common way is to use a store likereduxormobx. Withredux, you canconnectyour component to the store using a higher order component. Then, when your route'scomponent(which is really the HOC with your route component as its child) renders, it can grab up to date information from the store.I am not particularly familiar with
mobx, but from my understanding it can be even easier to setup. Usingredux,mobx, or one of the other state management is a great way to pass state throughout your application.Without A Store
What if you don't want to use a store? Are you out of luck? No, but you have to use an experimental feature of React: the
context. In order to use thecontext, one of your parent components has to explicitly define agetChildContextmethod as well as achildContextTypesobject. Any child component that wants to access these values through thecontextwould then need to define acontextTypesobject (similar topropTypes).You could even write your own higher order component that automatically injects the
contextvalues as props of your<Route>components. This would be something of a "poor man's store". You could get it to work, but most likely less efficiently and with more bugs than using one of the aforementioned store libraries.What about
React.cloneElement?There is another way to provide props to a
<Route>'scomponent, but it only works one level at a time. Essentially, when React Router is rendering components based on the current route, it creates an element for the most deeply nested matched<Route>first. It then passes that element as thechildrenprop when creating an element for the next most deeply nested<Route>. That means that in therendermethod of the second component, you can useReact.cloneElementto clone the existingchildrenelement and add additional props to it.This is of course tedious, especially if you were to need to pass this information through multiple levels of
<Route>components. You would also need to manage your state within your base<Route>component (i.e.<Route path='/' component={Base}>) because you wouldn't have a way to inject the state from parent components of the<Router>.