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
redux
ormobx
when 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.state
location.state
is 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
component
s? A common way is to use a store likeredux
ormobx
. Withredux
, you canconnect
your 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 agetChildContext
method as well as achildContextTypes
object. Any child component that wants to access these values through thecontext
would then need to define acontextTypes
object (similar topropTypes
).You could even write your own higher order component that automatically injects the
context
values as props of your<Route>
component
s. 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 thechildren
prop when creating an element for the next most deeply nested<Route>
. That means that in therender
method of the second component, you can useReact.cloneElement
to clone the existingchildren
element 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>
component
s. 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>
.