Flow Control

Learn how to use middleware for flow control.

One important usage of middleware is to control the application’s flow and logic. Let’s consider a sample user login flow:

  1. Send POST request to the server to log in
  2. Save access token in store
  3. Fetch current user’s profile information
  4. Fetch the latest notifications

Usually, our flow will begin with a LOGIN action containing the login credentials:

{
  type: 'LOGIN',
  payload: {
    email: 'info@redux-book.com',
    password: 'will-never-tell'
  }
}

After we successfully access the server, another action will typically be dispatched. Similar to:

{
  type: 'SUCCESSFUL_LOGIN',
  payload: 'access_token'
}

One of the reducers will make sure to update the access token in the state, but it is unclear who is responsible for issuing the two additional actions required: FETCH_USER_INFO and FETCH_NOTIFICATIONS.

We could always use complex action creators and the redux-thunk middleware in our login action creator:

const login = (email, password) => dispatch => {
  postToServer('login', { email, password })
    .then((response) => {
       dispatch(successfulLogin(response.accessToken));
       dispatch(fetchUserInfo());
       dispatch(fetchNotifications());
  });
};

But this might cause a code reuse problem. If in the future we want to support Facebook Connect, it will require a different action altogether, which will still need to include the calls to FETCH_USER_INFO and FETCH_NOTIFICATIONS. And if in the future we change the login flow, it will need to be updated in multiple places.

A simple solution to the problem is to dispatch two actions only after the login is successful. In the regular Redux flow, the middleware is the only actor that can listen for and react to events:

const loginFlowMiddleware = ({ dispatch }) => next => action => {
  // Let the reducer save the access token in the state
  next(action);

  if (action.type === SUCCESSFUL_LOGIN) {
     dispatch(fetchUserInfo());
     dispatch(fetchNotifications());
  }
};

Our new code holds the flow in a single place and will allow us to easily support login via Twitter, Google Apps, and more. In practice, we can combine flows and add conditions along with more complicated logic because we have full access to both dispatch() and getState().

A few external libraries that try to make flow management easier, such as redux-saga which tries to keep application side effects such as async functions manageable.

Get hands-on with 1200+ tech skills courses.