Using Higher Order Components for Authenticated Routing

Published Mar 28, 2018

A Higher Order Component (HOC) is just a React Component that wraps another one.

The react-redux connect(mapStateToProps, mapDispatchToProps)(Component) pattern is an example of using the connect() HOC to extend a React component such that its this.props is actually connected to values and actions in the Redux store.

Let's say we have some pages that we only want authenticated users to view it (a very common use case); we can use HOC here to handle this!

Let's define our requiresAuth HOC; assuming we are using the Redux store to store the auth status of the user:

./components/requiresAuth.js

import React, { PropTypes } from 'react';  
import { connect } from 'react-redux';  
import { push } from 'react-router-redux';

export default function (ComposedComponent) {  
  class Authenticate extends React.Component {
    static propTypes = {
      isAuthenticated: PropTypes.boolean,
      redirect: PropTypes.func.isRequired
    };

    componentDidMount() {
      this._checkAndRedirect();
    }

    componentDidUpdate() {
      this._checkAndRedirect();
    }

    _checkAndRedirect() {
      const { isAuthenticated, redirect } = this.props;

      if (!isAuthenticated) {
        redirect();
      }
    }

    render() {
      return (
        <div>
          { this.props.isAuthenticated ? <ComposedComponent {...this.props} /> : null }
        </div>
      );
    }
  }

  const mapStateToProps = (state) => {
    return {
      isAuthenticated: state.auth.isAuthenticated
    };
  };
  
  const mapDispatchToProps = dispatch => bindActionCreators({
    redirect: () => push('/signin')
  }, dispatch)
  
  Authenticate.propTypes = propTypes

  return connect(
    mapStateToProps, 
    mapDispatchToProps
  )(Authenticate);
}

So, requiresAuth is a function that takes ComposedComponent and returns AuthenticatedComponent. AuthenticatedComponent wraps the original component, plus it checks if the user already authenticated, in case he is not, it will redirect to /signup. Pretty straightforward eh?

Now we can use requiresAuth HOC and update our component where we have defined the routes:

./components/route.js

...
import requireAuth from './requiresAuth';
...
const routes = (  
  <Route path="">
    <Route path="/signin" component={SignIn} />
    ...
    <Route path="/app" component={requiresAuth(App)}>
      <Route name="dashboard" path="dashboard" component={Dashboard} />
      <Route name="profile" path="user-profile" component={UserProfile} />
    </Route>
    ...
  </Route>
);
Discover and read more posts from Sahil Mittal
get started