The Ultimate Cheat Sheet on Splitting Dynamic Redux Reducers

Velotio Technologies
Velotio Perspectives
5 min readAug 30, 2019

This post is specific to need for code-splitting in React/Redux projects. While exploring the possibility to optimize the application, the common problem occurs with reducers. This article specifically focuses on how do we split reducers to be able to deliver them in chunks.

What are the benefits of splitting reducers in chunks?

1) True code splitting is possible

2) Good architecture can be maintained by keeping page/component level reducers isolated from other parts of application minimizing the dependency on other parts of application.

Why Do We Need to Split Reducers?

1. For fast page loads

Splitting reducers will have and advantage of loading only required part of web application which in turn makes it very efficient in rendering time of main pages

2. Organization of code

Splitting reducers on page level or component level will give a better code organization instead of just putting all reducers at one place. Since reducer is loaded only when page/component is loaded will ensure that there are standalone pages which are not dependent on other parts of the application. That ensures seamless development since it will essentially avoid cross-references in reducers and throwing away complexities

3. One page/component

One reducer design pattern. Things are better written, read and understood when they are modular. With dynamic reducers, it becomes possible to achieve it.

4. SEO

SEO is a vast topic but it gets hit very hard if your website is having huge response times which happens in case if code is not split. With reducer level code-splitting, reducers can be code split on a split component level which will reduce the loading time of website thereby increasing SEO rankings.

What Exists Today?

A little googling around the topic shows us some options. Various ways have been discussed at https://stackoverflow.com/questions/32968016/how-to-dynamically-load-reducers-for-code-splitting-in-a-redux-application/33044701#33044701 .

Dan Abramov’s answer is what we are following in this post and we will be writing a simple abstraction to have dynamic reducers but with more functionality.

A lot of solutions already exists, so why do we need to create our own? The answer is simple and straightforward:

1) The ease of use

Every library out there is little catchy is some way. Some have complex api’s while some have too much boilerplate codes. We will be targeting to be near react-redux api.

2) Limitation to add reducers at top level only

This is a very common problem that a lot of existing libraries have as of today. That’s what we will be targeting to solve in this post. This opens new doors for possibilities to do code splitting on component level.

A quick recap of redux facts:

1) Redux gives us the following methods:
— “getState”,
— “dispatch(action)”
— “subscribe(listener)”
— “replaceReducer(nextReducer)”

2) reducers are plain functions returning next state of the application

3) “replaceReducer” requires the entire root reducer.

What we are going to do?

We will be writing abstraction around “replaceReducer” to develop an api to allow us to inject a reducer at a given key dynamically.

A simple redux store definition goes like the following:

Let’s simplify the store creation wrapper as:

What Does it Do?

“dynamicActionGenerator” and “isValidReducer” are helper function to determine if given reducer is valid or not.

For e.g.

isValidReducer(() => { return  ) // should return trueisValidReducer(1) //should return falseisValidReducer(true) //should return falseisValidReducer(“example”) //should return false

This is an essential check to ensure all inputs to our abstraction layer over createStore should be valid reducers.

“createStore” takes initial Root reducer, initial state, and enhancers that will be applicable to created store.

In addition to that, we are maintaining, “asyncReducers” and “attachReducer” on store object.

“asyncReducers” keeps the mapping of dynamically added reducers.

“attachReducer” is partial in above implementation and we will see the complete implementation below. The basic use of “attachReducer” is to add reducer from any part of a web application.

Given that our store object now becomes like follows:

Store:

- getState: Func- dispatch(action): Func- subscribe(listener): Func- replaceReducer(RootReducer): Func- attachReducer(reducer): Func- asyncReducers: JSONObject

Now here is an interesting problem, replaceReducer requires a final root reducer function. That means we will have to recreate the root reducers every time.
So we will create a dynamicRootReducer function itself to simply the process.

So now our store object becomes as follows:
Store:

- getState: Func- dispatch(action) : Func- subscribe(listener) : Func- replaceReducer(RootReducer) : Func- attachReducer(reducer) : Func

What does dynamicRootReducer do?
1) Processes initial root reducer passed to it
2) Executes dynamic reducers to get next state.

So we now have an api exposed as :
store.attachReducer(“home”, (state = {}, action) => { return state }); // Will add a dynamic reducer after the store has been created

store.attachReducer(“home.grid”, (state={}, action) => { return state}); // Will add a dynamic reducer at a given nested key in store.

Final Implementation:

Working Example: https://stackblitz.com/edit/react-pvk4xw?file=Hello.js

Further implementations based on simplified code:

Based on it I have simplified implementations into two libraries:

Conclusion

In this way, we can achieve code splitting with reducers which is a very common problem in almost every react-redux application. With the above solution, you can do code splitting on a page level, component level and can also create reusable stateful components which use redux state. The simplified approach will reduce your application boilerplate. Moreover, common complex components like grid or even the whole pages like login can be exported and imported from one project to another making development faster than ever!

*****************************************************************

This post was originally published on Velotio Blog.

Velotio Technologies is an outsourced software product development partner for technology startups and enterprises. We specialize in enterprise B2B and SaaS product development with a focus on artificial intelligence and machine learning, DevOps, and test engineering.

Interested in learning more about us? We would love to connect with you on ourWebsite, LinkedIn or Twitter.

*****************************************************************

--

--

Velotio Technologies
Velotio Perspectives

Velotio Technologies is an outsourced software and product development partner for technology startups & enterprises. #Cloud #DevOps #ML #UI #DataEngineering