You need to wrap your component using withRouter
to make the router object available to you.
const Component = withRouter(
React.createClass({
//...
})
)
<Route component={App}>
{/* ... other routes */}
</Route>
const App = React.createClass({
getInitialState() {
return { showBackButton: false }
},
componentWillReceiveProps(nextProps) {
const routeChanged = nextProps.location !== this.props.location
this.setState({ showBackButton: routeChanged })
}
})
Route matching happens in the order they are defined (think if/else if
statement). In this case, /about/me
will show the <UserPage>
component because /about/me
matches the first route. You need to reorder your routes if this happens. <About>
will never be reachable:
<Router>
<Route path="/:userName/:id" component={UserPage}/>
<Route path="/about/me" component={About}/>
</Router>
About
is now reachable:
<Router>
<Route path="/about/me" component={About}/>
<Route path="/:userName/:id" component={UserPage}/>
</Router>
If your routes look like:
<Route path="/">
<Route path="widgets" component={WidgetList} />
<Route path="widgets/:widgetId" component={Widget} />
</Route>
Then the path /widgets
will not be considered active when the current path is something like /widgets/3
. This is because React Router looks at parent routes rather than parent paths to determine active state. To make the path /widgets
active when the current path is /widgets/3
, you need to declare your routes as:
<Route path="/">
<Route path="widgets">
<IndexRoute component={WidgetList} />
<Route path=":widgetId" component={Widget} />
</Route>
</Route>
As an additional benefit, this also removes the duplication in declaring route paths.
You might see this if you are using React.cloneElement
to inject props into route components from their parents. If you see this, remove isRequired
from propTypes
for those props. This happens because React validates propTypes
when the element is created rather than when it is mounted. For more details, see facebook/react#4494.
You should generally attempt to use this pattern as sparingly as possible. In general, it's best practice to minimize data dependencies between route components.
There are multiple ways to do this depending on what you want specifically.
You can define additional props on <Route>
or on the plain route:
<Route foo="bar" />
These properties will then be available on this.props.route
on the route component, such as with this.props.route.foo
above.
You can define a middleware that injects additional props into each route component:
const useExtraProps = {
renderRouteComponent: child => React.cloneElement(child, extraProps)
}
You can then use this middleware with:
<Router
history={history}
routes={routes}
render={applyRouterMiddleware(useExtraProps)}
/>
You can export React context on a top-level provider component, then access this data throughout the tree on rendered components.
<ExtraDataProvider>
<Router history={history} routes={routes} />
</ExtraDataProvider>
Use match({ history, routes })
on the client side. See the server rendering guide.