How to design Redux apps for scalability and type-safety

Christian Lüdemann
4 min readJul 6, 2018

Previously I have written about three ways to use Redux, but how do you structure your Redux app for a scalable application?

Redux is good for state management in big applications because you get to decouple write from read and you are not dependent on passing data through (potentially) many levels of components. But structured the wrong way you will end up in a maintenance hell.

In this post, we will look at how to structure a Redux app for scalability, easy maintenance, and type-safety. The code is based on implementing these Redux best practices for an Angular TodoApp which can be found on my Github.

Put Redux code in the corresponding folder

In the Angular style guide, it is recommended to put the code in feature modules. In the same manner, you want to place your Redux code where it is used, for higher cohesion. I call this folder “Redux-API” and this folder should contain action, reducer, selector, state and epic for the corresponding feature.

State Class

The state class contains the state of a part of the application. Often you see this as an interface called “app state”, but I prefer to use a class so that the constructor can be used for setting the initial state.

Type-safe Actions

Actions are dispatching events which are handled by reducers or epics. As I explained in my post about three ways to use Redux I recommended using actions for dispatching events and not commands.

Generic Action class

The generic action class is a generic class used to specify an action with a generic type and payload property as these properties follow the Redux standards.

ActionTypes as enums

Even though action types are a string, they should provide a type-safe way for selecting the action type. This is done with string enums which can look like this:

Complete action code

A complete example of an action with the above guidelines is:

Type-safe Reducers

Reducers are pure functions that take in the previous state and an action and returns a new state. Many Redux apps enforce immutability by using eg. ImmutableJS for ensuring that only actions can change the state.

Reducers are split into multiple reducer functions, that easy take the previous state and an action and returns a new state.

The reducer class looks like this:

Selector classes for reusable and type-safe store selection

One of the biggest disadvantages with reactive apps is that the control flow of the app can be very confusing, meaning it can be very hard to grasp the consequences of dispatching an action because you don’t know where the application is subscribing to different parts of the Redux store.

Selector classes mitigate this problem by creating reusable selector classes. The makes it easier for other classes to reference a part of the application because they just need to inject the selector for the given app state part and it makes it easy to search for all the places in the application a specific part of the Redux store is subscribed to.

Epics

Epics are triggered with an action, just as reducers, but dispatches other actions and is used for eg, doing HTTP requests, where you want to update the loading and error state continuously as the HTTP request is performed. Epics are often used when an action is dispatched as a Command, which, as I have written about previously, is not something I recommend as it complicates control flow and services can often do the same a lot easier.

This is what an epic, that is dispatching 10 actions around in the application, feels like maintaining:

Wrapping up

In this post, we saw how to make your Redux applications more stable and maintainable by ensuring cohesion of the Redux code to where it belongs in the application as well as creating type-safety by statically type actions and reducers. Selecting values from the Redux store with selector classes is easier and more maintainable as the selector can be injected into the code and provide type-safe selections of the Redux Store.

Originally published at Christian Lüdemann IT.

--

--