Make Redux Store Magic With Some OOP Approach

Sergey Nikitin
4 min readMay 22, 2019

--

IT’S being a while since we started using Typescript in our project (thanks God!) and in fact it offers own way to develop applications. The thing is that ES6 and Typescript offer your code to be more object-oriented. Some people prefer more functional programming in JS but I feel like we can achieve more on the edge of both worlds — object-oriented programming and functional programming. In this article I want to share my way to describe redux stores in my ReactJS applications.

Redux is a brilliant useful library and by the way very simple, so we use it all the time with React. If you don’t know much about Redux t̶h̶e̶n̶ ̶c̶h̶e̶c̶k̶ ̶t̶h̶e̶ ̶c̶a̶l̶e̶n̶d̶a̶r̶,̶ ̶i̶t̶’̶s̶ ̶2̶0̶1̶9̶ ̶a̶l̶r̶e̶a̶d̶y̶ I would strongly recommend to dive into it, understand how it works and try in your projects. For Angular folks we have something pretty similar called NgRx.

Main thing Redux stays on is to have new state object every time store updates data, so I eventually see such lines:

This is how redux store usually looks like
And this is the reducer (one of)

Does anybody love this? I don’t. I don’t love all that switch-cases even if the Typescript will cover your back and will ask you to implement code for every action type. But. The most terrible thing here as to me is how we manipulate the state. We get a new state different ways. It might be lodash-ish state = _.clone(currentState) or more standard usage of spread-operator like state = { …currentState }. Or if you have more complex structure with another reducer in state, you need to clone it manually, so in complex case you need to have a clone function.

Also you might miss some properties to define like here we don’t have queryString defined in initialState so we can’t see full picture on what exactly this state includes. In case we have more than just updating some property — that switch block goes bigger and bigger.

So what I prefer to do with all this stuff? Let’s think how we can improve it and make more sense of the code.

First of all, let’s create our state. We are about to wrap the state into class without any methods as Redux requires to have state as a plain object:

Here is our new state!

What can we see here? We fully described our state (thank you, Typescript!) and also now we have a static clone() method related to a particular state class. So we 100% know how to clone it and we know what will happen in case we want to clone it.

Next, we are now able to define our reducer. But, before we do it, I will create an abstract core-reducer which will handle some basic logic for other ones I will create in the future:

A core reducer is like this

I just defined here that each of my reducers must have a handler to initialise the first state and also must have a list of actions and handler this reducer should process. The changeState thing does exactly that: it gets an action, looks for a proper handler in case it exist and then applies transformation. Simply as that.

Just by the way I added callAction function to throw actions from anywhere I want to!

Huh, let’s return to our reducer. Now we can inherit from the core reducer and make it work:

Easy as that

We defined handlers by action id and asked to create initial state. Easy! We now can clone current state and transform it whatever we want. We also can forget about action ids at all since we have functions which will call proper action for us!

And as the final step, we need to combine our reducer with other ones and set up our application

That’s it. We just created a reducer instance and use changeState to listen for any actions in Redux.

To finalise what we achieved:

  • We use Typescript to describe our Redux state so we totally understand what it contains and cannot have a mistake by storing something wrong;
  • We use classes to collect related things such as cloning methods for particular state;
  • We use inheritance to extract common logic from our reducers so we can reuse it and allow particular reducer to do its own stuff;
  • We have a clean understanding what is going on, each handler now represents dedicated function, we don’t need to expose internal action ids somewhere in React components;

So we basically took process in control and made things transparent and readable. Bringing some OOP stuff into your application may unveil ways to improve or at least might help to look at the code from the other side.

Which kind of approach do you prefer the most while using Redux in your projects? Let’s discuss in comments!

Hey, my name is Sergey and I make frontend great at Ixtens company in snowy Novosibirsk. Thank you for reading my article — I hope it was useful. Stay tuned for my new posts and reach me out in case of any questions.

--

--

Sergey Nikitin
Sergey Nikitin

Written by Sergey Nikitin

Frontend eng @ Miro.com | Amsterdam, NL. TypeScript, Angular, React, Webpack, NodeJS. We also can talk about surfing or snowboarding twitter.com/n0th1ng_else