0
votes

I'm new to backend programming and building my first full stack project and using Express/Mongoose/Mongo and Passport.js for the first time.

I have built "sign in with Github" functionality and have everything with Passport set up. Now I want to use Redux to store whether or not a user is logged in. If the user is logged in I want to change my navigation bar i.e. if the user isn't logged in one link says "log in", but if the user is logged in the "log in" link changes to "profile".

I know I can use the ternary operator in my React component to toggle the link depending on whether the user is logged in.

How do I use Redux to store whether a user is logged in? Here's what I have so far:

Redux action:

export function loggedIn() {
    return {
      type: "LOGGED_IN",
      loggedIn: false
    }
};

Redux reducer:

export default function reducer(state = {
  loggedIn: false
}, action) {
  switch(action.type) {
    case "LOGGED_IN": {
      return {
        ...state,
        loggedIn: true
      }
    }
    case "LOGGED_OUT": {
      return {
        ...state,
        loggedIn: false
      }
    }
    default: return state;
  }

}

I'm my Express route I am using the following middleware:

// Checks if user is not logged in
const authCheck = (req, res, next) => {
    if(!req.user) {
      // If user is not logged in, redirect them to login page
      res.redirect('/auth/login');
    }
    else {
      // If user is logged in call next in router.get

      // Would this be the proper place to dispatch to the Redux store 
      // whether a user is logged in?
      dispatch(loggedIn(true));
      // After updating the Redux store call next()
      next();
    }
};

How can I properly store in state whether the user is logged in/out and then access this state in the React component so I can use the ternary operator to choose whether to display "logged in" or "profile" in my navigation bar?

2

2 Answers

1
votes

It is advisable not to mix your backend routes with the reducer dispatch. I would suggest sending back a response res.status(200).send({ loggedIn: true }) in your middleware.

// Checks if user is not logged in
const authCheck = (req, res, next) => {
    if(!req.user) {
      // If user is not logged in, redirect them to login page
      res.redirect('/auth/login');
    }
    else {
      res.status(200).send({ loggedIn: true })
      next();
    }
};

The call to this middleware can then dispatch a success based on the response.

 if (res.status === 200) {
  dispatch(loggedIn(res.loggedIn));
 }
 else {
  dispatch({ type: 'LOGIN_FAILED'})
 }
0
votes

You should just handle your authentication state in your react frontend. Even if your are doing server side auth, its better to just have the authentication state saved in your React frontend with Redux. In your react app:

You will also need to use the react-redux library to connect react with redux

Actions

export const login_success = () => {
  return {
    type: ACTION_TYPES.LOGIN_SUCCESS
  }
}

export const login_failure = () => {
  return {
    type: ACTION_TYPES.LOGIN_FAILURE
  }
}

reducer:

const initialState = {
  isAuthenticated: false,

}


const AuthReducer = (state= initialState, action) => {
  switch(action.type) {
    case ACTION_TYPES.LOGIN_SUCCESS:
      return {
        ...state,
        isAuthenticated: true
      }
    case ACTION_TYPES.LOGIN_FAILURE:
      return {
        ...state,
        isAuthenticated: false
      }
}

Access the auth state with props

 {this.props.isAuthenticated
         ? <h3> user is logged in </h3>
         : <h3> user is not logged in </h3>
       }

function mapStateToProps(state) {
  return {
     isAuthenticated: state.auth_reducer.isAuthenticated
  }
}

Implement this in a callback component that is rendered after the user signs in.

function mapDispatchToProps(dispatch) {
  return {
    action1: () => dispatch(ACTIONS.LOGIN_SUCCESS),
  }
}

If you want a fully functioning example of how to do this you can check out this project I built, it is a full stack react express app with authentication

https://github.com/iqbal125/react-redux-fullstack-blog

To give you some tough love, it seems to me you dont fully understand Redux, I would suggest mastering Redux before trying to build a complex full stack app, just a suggestion.

Edit:

Communication with server can be done with a proxy, so in your package.json in your react app you can do:

"proxy": http://localhost:5000"

or wherever your node server is running. You can also just send back a server response to your React frontend, anything at all, then update your React-Redux frontend based on that server response.

So in your express server

router.get('api/login', (req, res) => { 
  if(res.login === true) { 
    res.json(success_login: true)
  }
})

then in your react frontend

axios.get('/api/login')
  .then(res => this.props.login_success(res.data) )

login_success(res) {
  if(res.success_login === true) {
    type: "SUCCESS_LOGIN"
} 

So essentially you will not handle any routing or redux authentication state in your express server. Your server will send a response to your react frontend and then the routing and redux authentication state will be handled by your frontend.