Simplify Redux Actions with Middleware

Comparing Flux with Redux

Working with React, we compared flux with redux, our team decided to use redux. The devtools redux offers was icing on the cake. Diving in, we wanted a central location for all of our API calls. The API middleware would need to handle dispatching a pre-request, successful request, and failures. To handle this, we set our actions in the following format


import DT_API_CALL from '../middleware/api';

export function fetchUser(userId) {
    return {
       [DT_API_CALL]: {
           types: [USER_REQUEST, USER_SUCCESS],
           endpoint: '/user/${userId}',
           method: 'get'

export function saveUser(user) {
    return {
        [DT_API_CALL]: {
            types: [USER_REQUEST, USER_SUCCESS],
            endpoint: '/user/update',
            method: 'put',
            data: user

Configure middleware

Configuring our middleware looks something like:

export default store => next => action => {
const apiCall = action[DT_API_CALL];
 if (typeof apiCall === 'undefined') { return next(action); }
return callApi(apiCall).then(
  response => next(actionWith({payload: response, type: successAction})),
 errors => ({errors, type: ServerActions.SERVER_FAILURE}));

I’ve removed some code for brevity, the main point is displayed. We make an axios API call and handle the response in the middleware dispatching to the correct action handler, or reducer.

Configure store

To configure our store so that it knows about our middleware we simply do the following:

import api from '../middleware/api';
const finalCreateStore = compose(
    applyMiddleware(thunk, api))(createStore);

Inside our compose we just need to add our API middleware. Now our API will be called after our actions and before our reducers.


Now that our API is configured we can use it to fetch a user.

import UserActions from '../actions/UserActions';
const mapDispatchToProps = (dispatch) => ({
    actions: bindActionCreators(UserActions, dispatch)

class UserDisplay extends React.Component {
   componentWillMount() {
      // we can now use this.props.user.currentUser
export default connect(state => state, mapDispatchToProps)(UserDisplay);

All we have left is our reducer.


The reducer is where we handle updating the data in our state. The reducer is pretty simple to setup.

import * as UserActions from '../actions/UserActions';
export default function user(state = {
   currentUser: null
}, action) {
   switch (action.type) {
      case UserActions.USER_SUCCESS:
         return Object.assign({}, state, {
            currentUser: action.payload
      default: return state;

For our server errors, we would create a serverError reducer and pull in the ServerActions. Then handle setting errors on a SERVER_FAIL action dispatched from our middleware.



Working with state on the client can become difficult, however, redux greatly simplifies this. Don’t forget to checkout the devtools too, they are a huge help in identifying state changes and how the UI is responding.

Gary L. Cox, Jr.


%d bloggers like this: