Rethinking Redux (and reducing its boilerplate)
Tags: redux, react
Published: 2017-03-29 18:25:33

---
title: "Rethinking Redux (and reducing its boilerplate)"
published: true
description: How to make a single function to generate a reducer, action creators, and types
cover_image: https://drscdn.500px.org/photo/157723175/m%3D900/51760a7ea86957308bbcfdbd47831f94

tags: redux, react
---
_tl;dr: [redux-create-module](https://github.com/Emilios1995/redux-create-module)_

Suppose you want to create a new module in your react-redux app.
You know the drill.
Create the action type constants, make and the action creators, and handle the types in the reducer.
You may have noticed that the process looks the same _almost_ every time.
We, as developers, know that this kind of things could, and should be abstracted and automated.

So, first let's think what's the best solution for Developer Experience.
Or, since _we are_ the Developers, let's just Rethink Redux.

Well, if we are only interested in *mapping* actions to states, my first thought is to make a *Map*. Or a regular object, for that matter.

```js
const counterMap = {
  increment: (state) => state + 1,
  decrement: (state) => state -1
}
// How do we use it? Simple. With a reducer.
const reducer = (state = 0, action) => 
  (counterMap[action.type]) 
    ? counterMap[action.type](state) 
    : state
```
But we don't want to create the reducer. We only want to think about the Map. Let's make a function that takes a Map and returns a reducer

```js
const createReducer = (initialState, map) =>
   (state = initialState, action) => 
     (map[action.type]) 
       ? map[action.type](state) 
       : state

const reducer = createReducer(0, counterMap)

reducer(0, {type: "increment"}) // => 1
```
So simple! Or, too simple! Because we have a problem here. Action creators were invented for a reason, and that's because some actions need to have a payload to be handled... Or is it? 
No! of course, there is another reason and that's because it's unsafe and ineffective to pass strings to the reducer. What if we make a typo on it?!
So *let's get more serious now.*

We still don't want to create the action creators manually, and, why should we?
Think about it, `createReducer` already has all the information it needs to make them. 
It can get the types of our actions from the `keys` of the Map. 
So, let's make it return both, a reducer and the action creators, and name it `createModule`

```js
const createModule = (initialState, map) => {
  const reducer = (state = initialState, action) => 
     (map[action.type]) 
       ? map[action.type](state) 
       : state
  const actions = Object.keys(map).reduce(
    (acc, type) =>
      Object.assign(acc, {
        [type]: (payload = {}) => ({ type, payload })
      }),
    {}
  );
}  
// example
const counterMap = {
  add: (state, {payload}) => state + payload
}
export const counter = createModule(0, counterMap)

// then somewhere in a connected component...
dispatch(counter.actions.add(2))
```

Neat!

Of course, we still have some todos. like namespacing our actions to avoid conflicts, and allowing a reducer to handle an action from another module.
But we won't get into that in this post. 

Instead, I'll refer you to the source of the [little module](https://github.com/Emilios1995/redux-create-module) I made.

Thanks for reading!

_Photo: [Sunrise in the Sea](https://500px.com/photo/157723175/sunrise-in-the-sea-by-emilio-srougo) by me :)_