We’re going to overview evolution of reducers in my Redux/NGRX apps that took place over the last two years. Starting from vanilla switch-case , going to selecting a reducer from an object by key, finally settling with class-based reducers. We're not going to talk only about how, but also about why.

If you’re interested in working around too much boilerplate in Redux / NGRX you might want to check this article out. If you’re already familiar with selecting a reducer from a map technique consider jumping right to class-based reducers.

Vanilla switch-case

So let’s take a look at an everyday task of creating an entity on the server asynchronously. This time I suggest we describe how we could create a new jedi.

Let me be honest, I’ve never used this kind of reducers in production. My reasoning is threefold:

switch-case introduces some points of tension, leaky pipes, which we might forget to patch up in time at some point. We could always forget to put in break if do not do immediate return , we could always forget to add default , which we have to add to every reducer.

introduces some points of tension, leaky pipes, which we might forget to patch up in time at some point. We could always forget to put in if do not do immediate , we could always forget to add , which we have to add to every reducer. switch-case has some boilerplate code itself which doesn't add any context.

has some boilerplate code itself which doesn't add any context. switch-case is O(n), kind of. It is not a solid argument by itself because Redux is not very performant anyway, but it makes my inner perfectionist mad.

The logical next step which Redux’s official documentation suggests to take is to pick a reducer from an object by key.

Selecting a reducer from an object by key

The idea is simple. Each state transformation is a function from state and action and has a corresponding action type. Considering that each action type is a string we could create an object, where each key is an action type and each value is a function that transforms state (a reducer). Then we could pick a required reducer from that object by key, which is O(1), when we receive a new action.

The cool thing here is that logic inside reducerJedi stays the same for any reducer, which means we can re-use it. There's even a small library, called redux-create-reducer, which does exactly that. It makes the code looks like this:

Nice and pretty, huh? Though this pretty still has a few caveats:

In case of complex reducers we have to leave lots of comments describing what this reducer does and why.

Huge reducer maps are hard to read.

Each reducer has only one corresponding action type. What if I want to run the same reducer for several actions?

Class-based reducer became my shed of light in the kingdom of the night.

Class-based reducers

This time let me start with whys of this approach:

Class’ methods will be our reducers and methods have names, which is a useful meta-information, and we could abandon comments in 90% of cases.

Class’ methods could be decorated which is an easy-to-read declarative way to match actions and reducers.

We still could use a map of actions under the hood to have O(1) complexity.

If that’s sounds like a reasonable list of reasons for you, let’s dig in!

First of all, I would like to define what we want to get as a result.

Now as we see where we want to get we could do it step by step.

Step 1. @Action decorator.

What we want to do here is to accept any number of action types and store them as meta-information for a class’ method to use later. To do that we could utilize reflect-metadata polyfill, which brings meta-data functionality to Reflect object. After that this decorator would just attach its arguments (action types) to a method as meta-data.

Step 2. Creating a reducer function out of a reducer class

As we know each reducer is a pure function that accepts a state and an action and returns a new state. Well, class is a function as well, but ES6 classes can not be invoked without new and we have to make an actual reducer out of a class with a few methods anyway. So we need to somehow transform it.

We need a function that would take our class, walk through each method, collect metadata with action types, build a reducer map and create a final reducer out of that reducer map.

Here’s how we could examine each method of a class.

Now we want to process the received collection into a reducer map.

So the final function could look something like this.

And we could apply it to our ReducerJedi class like this.

Step 3. Merging it all together.

Next steps

Here’s what we missed:

What if the same action corresponds to several methods? Current logic doesn’t handle this.

Could we add immer?

What if I use class-based actions? How could I pass an action creator, not an action type?

All of it with additional code samples and examples is covered with reducer-class.

I must say using classes for reducers is not an original thought. @amcdnl came up with awesome ngrx-actions quite a while ago, but it seems like he’s now focused on NGXS, not to mention I wanted more strict typing and decoupling from Angular-specific logic. Here’s a list of key differences between reducer-class and ngrx-actions.

If you like the idea of using classes for your reducers, you might like to do the same for your action creators. Take a look at flux-action-class.

Hopefully, you found something useful for your project. Feel free to communicate your feedback to me! I most certainly appreciate any criticism and questions.

UPD #1: Take a look at this discussion on reddit to hear other arguments made for and against this approach