I was trying to implement authenticated routes but found that React Router 4 now prevents this from working:
<Route exact path="/" component={Index} />
<Route path="/auth" component={UnauthenticatedWrapper}>
<Route path="/auth/login" component={LoginBotBot} />
</Route>
<Route path="/domains" component={AuthenticatedWrapper}>
<Route exact path="/domains" component={DomainsIndex} />
</Route>
The error is:
Warning: You should not use
<Route component>
and<Route children>
in the same route;<Route children>
will be ignored
In that case, what's the correct way to implement this?
It appears in react-router
(v4) docs, it suggests something like
<Router>
<div>
<AuthButton/>
<ul>
<li><Link to="/public">Public Page</Link></li>
<li><Link to="/protected">Protected Page</Link></li>
</ul>
<Route path="/public" component={Public}/>
<Route path="/login" component={Login}/>
<PrivateRoute path="/protected" component={Protected}/>
</div>
</Router>
But is it possible to achieve this while grouping a bunch of routes together?
After some research, I came up with this:
import React, {PropTypes} from "react"
import {Route} from "react-router-dom"
export default class AuthenticatedRoute extends React.Component {
render() {
if (!this.props.isLoggedIn) {
this.props.redirectToLogin()
return null
}
return <Route {...this.props} />
}
}
AuthenticatedRoute.propTypes = {
isLoggedIn: PropTypes.bool.isRequired,
component: PropTypes.element,
redirectToLogin: PropTypes.func.isRequired
}
Is it correct to dispatch an action in render()
? It feels wrong. It doesn't really seem correct with componentDidMount
or some other hook, either.
You're going to want to use the Redirect
component. There's a few different approaches to this problem. Here's one I like, have a PrivateRoute component that takes in an authed
prop and then renders based on that props.
function PrivateRoute ({component: Component, authed, ...rest}) {
return (
<Route
{...rest}
render={(props) => authed === true
? <Component {...props} />
: <Redirect to={{pathname: '/login', state: {from: props.location}}} />}
/>
)
}
Now your Route
s can look something like this
<Route path='/' exact component={Home} />
<Route path='/login' component={Login} />
<Route path='/register' component={Register} />
<PrivateRoute authed={this.state.authed} path='/dashboard' component={Dashboard} />
If you're still confused, I wrote this post that may help - Protected routes and authentication with React Router v4