How to add protected routes in react redux

I have created a login component on which I have all the logic stuff.

The login reducer is:

const openState = {
  loggedIn: null,
  user: null
}

export default (state = openState, action) => {
  switch (action.type) {
    case LOGIN:
      return { ...state, loggedIn: true, user: action.payload }
    case LOGOUT:
      return { ...state, loggedIn: false, user: null }
    default:
      return openState
  }
}

The Action :

export const logIn = (user) => {
  return {
    type: LOGIN,
    payload: user
  }
}

export const logOut = () => {
  return {
    type: LOGOUT
  }
}

everything is working just fine but I’m not sure how to pass the loggedIn and user props from action into the routes component in order to secure all routes:

const MainRoutes = props => {
  const { loggedIn } = props;

  console.log(props.loggedIn)

return (
  <Router history={history}>
    <Baseline />
    <Menu/>
    <Container maxWidth="md">
      <Switch>
        <Route exact path="/Login" component={Login} />
        <Route exact path="/Carousel" component={Carousel} />
        <Route exact path="/Stepper" component={Stepper} />
        <Route component={NotFound} />
      </Switch>
    </Container>
  </Router>
);
}

const mapStateToProps = (state) => {
return { loggedIn: state.loggedIn };
};

export default connect(mapStateToProps)(MainRoutes);

If I’ll console.log the loggedIn props I get undefined 😐
Based on loggedIn I can create a logic into the routes component.

5 thoughts on “How to add protected routes in react redux”

  1. You could simply define a custom ProtectedRoute component that’ll be connected to redux state. In your case it should map state.auth.loggedIn and state.auth.user to props and perform a Redirect if those values are falsy:

    import React from "react";
    import { Route, Redirect } from "react-router-dom";
    import PropTypes from "prop-types";
    
    
    const ProtectedRoute = (props) => {
      const { redirectPath, component, user, loggedIn, ...routeProps} = props;
      const Component = component;
      const isAccessible = Boolean(user) && loggedIn;
    
      return (
        <Route
          {...routeProps}
          render={props => {
            if (isAccessible) return <Component {...props} />;
            return <Redirect to={{ pathname: redirectPath || "/Login" }} />;
          }}
        />
      );
    };
    
    ProtectedRoute.propTypes = {
      path: PropTypes.string.isRequired,
      redirectPath: PropTypes.string,
      component: PropTypes.oneOfType([
        PropTypes.shape({ render: PropTypes.func.isRequired }),
        PropTypes.func
      ]),
    };
    
    const mapStateToProps = (state) => {
      return { 
        loggedIn: state.auth.loggedIn, 
        user: state.auth.user 
      };
    };
    
    export default connect(mapStateToProps)(ProtectedRoute);
    

    With this in place your MainRoutes won’t need connect anymore:

    const MainRoutes = props => {
      return (
        <Router history={history}>
          ...
          <Container maxWidth="md">
            <Switch>
              <Route exact path="/Login" component={Login} />
              <ProtectedRoute exact path="/Carousel" component={Carousel} />
              <ProtectedRoute exact path="/Stepper" component={Stepper} />
              <Route component={NotFound} />
            </Switch>
          </Container>
        </Router>
      );
    }
    
    export default MainRoutes;
    
    Reply
  2. What I would do in this scenario is to create a private route basically, which would only be accessible if you are logged in, or in your case, if the loggedIn in your loggedIn: state.loggedIn is true and if a user exists in state.auth.user. And if both are false, it will redirect you to the /login page to login or signup first before accessing those private routes.

    So to create a private route or a <PrivateRoute />,

    import React from 'react';
    import { Route, Redirect } from 'react-router-dom';
    import PropTypes from 'prop-types';
    import { connect } from 'react-redux';
    
    
    const PrivateRoute = ({ 
      component: Component,
      auth: { user, loggedIn },
      ...rest 
    }) => (
      <Route 
        {...rest} 
        render={props => 
          loggedIn && Boolean(user) ? (
            <Component {...props} />  
          ) : (
            <Redirect to="/login" />
          )
        } 
      />
    );
    
    PrivateRoute.propTypes = {
      auth: PropTypes.object.isRequired
    }
    
    const mapStateToProps = state => ({
      auth: state.auth
    });
    
    export default connect(mapStateToProps)(PrivateRoute);
    

    This will create that private route or <PrivateRoute /> for you which you can import into your MainRoutes file and then you can pass on the components to it which are supposed to be protected by the private route.

    const MainRoutes = props => {
      return (
        <Router history={history}>
          <Baseline />
          <Menu/>
          <Container maxWidth="md">
            <Switch>
              <Route exact path="/Login" component={Login} />
              <PrivateRoute exact path="/Carousel" component={Carousel} />
              <PrivateRoute exact path="/Stepper" component={Stepper} />
              <Route component={NotFound} />
            </Switch>
          </Container>
        </Router>
      );
    }
    
    export default MainRoutes;
    

    This way the components to be protected will check if the user exists and if you are logged in or not and if true, it will let you access those components.

    Reply

Leave a Comment