2

I'm setting up redux in my app, and am starting with log in. So far I've got it working great - user logs in using Google, on success my server returns an access token to the web app that is put into the redux store, and can then be used for future API calls.

What I would like is for the webapp to immediately request the current users profile in response to storing the access token. It needs to be after the access token is stored though - so after the reducer is called.

In essence, in response to the AUTHENTICATED action, I'd like to dispatch the LOAD_USER action - which itself is promise based, so the LOAD_USER_RESOLVED action then eventually gets triggered to store the newly logged in user into the store, which will then display their name in the UI.

I'm using redux-promise-simple at the moment, but if that needs to change there not a problem.

Graham
  • 4,095
  • 4
  • 29
  • 37

1 Answers1

1

When I usually need to chain something like authentication actions, I put some logic in a connected login component. I would set a boolean that would change from false to true in my AUTHENTICATED redux action. And have the component listen to that value. When the value were to change to true, I would fire off the second action.

Example:

    // Auth reducer
export const authentication = (
  state = {
    authenticated: false,
    identity: null,
    token: null,
    loading: false,
  },
  action,
) => {
  switch (action.type) {
    case types.LOGIN:
      return {
        ...state,
      };
    case types.AUTHENTICATED:
      return {
        ...state,
        authenticated: true,
        token: action.result.data,
      };
    case types.LOAD_USER:
      return {
        ...state,
        loading: true,
      }
    case types.LOADED_USER:
      return {
        ...state,
        loading: false,
        identity: action.result.data
      }
    default: return state;
  }
}


//Connected component:
import { loadUser } from 'actions';

class Login extends React.Component {

  componentWillMount() {
    const { token, authenticated } = this.props;
    if (authenticated && token ) {
      // Dispatch your action here;
      loadUser(token);
    }
  }
  componentWillReceiveProps(nextProps) {
    const { token, authenticated } = nextProps;
    const { loadUser } = this.props;
    if (authenticated && token ) {
      // Dispatch your action here;
      loadUser(token);
    }
  }
  ...

  ...

  mapStateToProps(state) {
    const { token, authenticated } = state.authentication
    return {
      authenticated,
      token
    }
  }

  export default connect(mapStateToProps, { loadUser })(Login)

Edit: If you would rather chain actions together rather than have a component listen on the redux store to dispatch an action. Take a look at the redux-thunk library here, it is a useful thunk middleware, and has some really useful examples of chaining async actions there.

Yo Wakita
  • 5,322
  • 3
  • 24
  • 36
  • I've seen that suggestion before. It just feels a bit wrong to rely on UI components to trigger one store update based on another one happening. It feels like that belongs either in the store itself or else in the action creators.. – Graham Feb 24 '17 at 07:24
  • It can definitely also be done via chaining actions in the action creator as well. I prefer to have my actions more decoupled and find that the action creators stay more concise when I set up my application this way. I'll edit my post so that there is an example of chaining together async actions, but in the meantime there is a good discussion with examples here: https://github.com/reactjs/redux/issues/1676 – Yo Wakita Feb 24 '17 at 07:52
  • I suspect that redux-thunk is going to be the answer. Thank you :) – Graham Feb 24 '17 at 12:41