Quick Tip: alternative Redux reducers

I have been using a simple helper to simplify and reduce boilerplate for setting up reducers in Redux.

Redux reducers

What could be improved on the default “switch reducers”

Lets take a look at a default switch reducer:

orders.js

import { ORDERS_LOAD } from '../constants/ActionTypes';

const initialState = {
  data: [],
  error: false,
  pending: false
};

export default function ordersReducer (state = initialState, action) {
  switch (action.type) {
    case ORDERS_LOAD + '_PENDING':
      return {
        ...state,
        error: false,
        pending: true
      };
    case ORDER_LOAD + '_ERROR':
      return {
        ...state,
        error: action.error,
        pending: false
      };
    case ORDERS_LOAD + '_SUCCESS':
      return {
        ...state,
        data: action.payload,
        pending: false
      };
    default:
      return state;
  }
}

What could be improved:

  • I really don’t like switch statements, especially when they get bigger
  • An action always has to return the original state
  • The default case always has to return the state, why do we need to add this in every reducer?

Lets improve the reducers boilerplate

Take a look at the helper that I have been using in most of my projects which simplifies the reducers:

createreducer.js

export default function createReducer (initialState, actions) {
  return function reducer (state = initialState, action) {
    const reduce = actions[action.type];

    if (!reduce) {
      return state;
    }

    return {
      ...state,
      ...reduce(state, action)
    };
  };
}

Now lets convert the switch reducer to our new optimized reducer:

orders.js

import { createReducer } from '../helpers/createReducer';
import { ORDERS_LOAD } from '../constants/ActionTypes';

const initialState = {
  data: [],
  error: false,
  pending: false
};

export default createReducer(initialState, {
  [ORDERS_LOAD + '_PENDING']: () => ({
    ...initialState,
    pending: true
  }),
  [ORDERS_LOAD + '_SUCCESS']: (state, { payload }) => ({
    pending: false,
    data: payload
  }),
  [ORDERS_LOAD + '_ERROR']: (state, { error }) => ({
    pending: false,
    error
  })
});

Final thoughts

So as you can see we cleaned up the reducer. I suggest you create a createReducer.js helper and play around with it, it made my code more readable which is imo the most important thing.

Enjoy writing less boilerplate code for your Redux reducers.

Cheers.