Trick: alternative Redux reducers

In this article, I'll share a quick trick with you to clean up your Redux reducers. One thing I don't like about Redux is all the boilerplate, are you with me?

Trick: alternative Redux reducers

I’ve been using a simple helper to simplify and reduce boilerplate for creating reducers in Redux.

What could be improved with the default “switch reducers”

Lets take a look at a default switch reducer:

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’s wrong with this:

  • The switch statements are pretty ugly and unreadable, especially when they get bigger: you end up with splitting the reducer into functions, and in the switch statement calling those functions.
  • An action always has to return the original state, why do we need to do this everytime?
  • The default case always has to return the state, why do we need to add this in every reducer?

Let’s improve the reducers boilerplate

Take a look at the following helper that I’ve using in most of my projects which simplifies the reducers:

function createReducer(initialState, handlers) {
  return function reducer(state = initialState, action) {
    if (handlers.hasOwnProperty(action.type)) {
      return handlers[action.type](state, action)
    }

    return state
  }
}

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

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!

Mike Vercoelen

“I am a self-proclaimed
Internet Creative”

Originally from The Netherlands, I am a self-taught web-app and blockchain professional with more than a decade of industry experience.

I have worked with a diverse collection of large-scale companies in finding streamlined solutions for complex problems.

I am specialised in software architecture, solutions, tooling and development of websites and applications, I am an expert in React, React Native, Typescript, Node.js, Solidity, GraphQL and UI / UX Design.

Subscribe to Codersmind

Do you want to receive high quality posts every week?