Warning: The following answer uses React's old context API. If you are using V16.3+, the following answer does not apply to you
Ok, so, according to your logic, unauthorized users are prohibited to access the User component. Simple and fair. No problems with that.
But my concern is that are you checking if the user is logged in inside a component which unauthenticated users should not get into. This is incorrect in my opinion because:
It's an extra journey for our program - adds an extra bit of unnecessary inefficiency. There is a possibility that from the router we go to User component and the latter sends us back to the former. Ping pong.
The User component looks dirty. Having irrelevant logic. Yes irrelevant. Because authentication check should not be done in User component. User component should contain user related stuff.
What do you think if instead of getting inside the User component to check users authentication, we check this in the router? User component, as it name describe, is dedicated for users and the logic to check authentication should be taken out from there.
Ok, Thats cool. But how?
We can create a Higher-Order Component (HOC) which as an argument will take any component was pass to it. Then, we add authentication logic inside the HOC and finally, depending on the logic we use we can either redirect to the homepage or allow the request to the given component.
In order for the HOC to be able to do the above it needs access to:
- State. We need to know whether the user is logged in and the state is where we store such data.
- Router. We may need to redirect users.
Lets name the HOC required_auth
. Here is the code of it:
import React, { Component } from 'react';
import { connect } from 'react-redux';
export default function(ComposedComponent) {
class Authentication extends Component {
static contextTypes = {
router: React.PropTypes.object
}
componentWillMount() {
if (!this.props.authenticated) {
this.context.router.history.push('/');
}
}
componentWillUpdate(nextProps) {
if (!nextProps.authenticated) {
this.context.router.history.push('/');
}
}
render() {
return <ComposedComponent {...this.props} />
}
}
function mapStateToProps(state) {
return { authenticated: state.auth.authed };
}
return connect(mapStateToProps)(Authentication);
}
As you can see, there is no black magic happening here. What might be confusing is
static contextTypes = {
router: React.PropTypes.object
}
context
is similar to props
but it allows us to skip
levels in our component hierarchy
Because this.context
is very easy to access and abuse, React forces us to define the context in this way.
Do not use context unless you really know what you are doing. The use case for context is not that common. Read more on what the consequences could be here
To conclude on our HOC, it simply takes a component as an argument and it either redirect to the homepage or returns the component that we will pass to it.
Now to use it, in route file we import the HOC
import RequiredAuth from './components/auth/required_auth';
and any routes which we want to protect from non-authoirzed users we simply route it like this:
<Route path="/user" component={RequiredAuth(User)}/>
The line above will either direct to homepage or returns the component which we are passing, User
References:
https://facebook.github.io/react/docs/higher-order-components.html
https://facebook.github.io/react/docs/context.html