DEV Community

Ashish Surana
Ashish Surana

Posted on

Refactoring Redux - A clever way

Redux is a A predictable state container for JavaScript apps.

Also, Redux is a nice example of simple functional programming paradigm where we use pure functions for data mutation. Or we can say, by using functional programming we can be more predictable and eventually less errors (This is what makes me happy).

Redux became popular exponentially along with the react.js. However, It can be used with any application and it is independant of Any front end technology.

Clutter starts from here
As our Product managers enrich application with new features, our store experiences the maximum impact due to this. Length of Reducers grows linearly along with the source code. The no. of cases inside the switch blocks keep on increasing and in many cases reducer file length crosses 700, 900 lines.
Our objects dives in deep level of nesting, Updation of nested objects become a pain, And now Our Clean reducer became a big ball of mud. So after Looking for solutions, I end up finding few tips for redux refactoring

  1. Using functions to return new state inside switch cases
  2. Flat State shape inside a reducer
  3. using combineReducer to club multiple reducers

Let's discuss if they can really help us in refactoring

Using functions: This can be a great way of clean code. We can import pure functions and use them in our reducers, but still our noumber of switch cases are intact. Biggest problem with this approach is it can affect readability because now our state and state mutation lies in separate files.
so what's next?????

Flat State shape: This must be kept in mind while designing and creating reducer states. Less level of nesting will lead to a cleaner store. But what if our reducer is already messed up with deep level of objects and actions to mutuate those objects??? Changing structure is almost next to impossible because it will affect all connected components.
How about combining Reducers???

Combine Reducers: This is a great way to club multiple reducers under a single key name, but this is also not a feasible approach for existing messed up reducers, because the challenge with this is it contains all reducers under a key Reducers, and if we want to add combineReducer function, then we have to make every state object a reducer

const rootReducer = combineReducers({
  firstNamedReducer,
  nested: combineReducers(reducerA, reducerB, reducerC),
  secondNamedReducer
})

const store = createStore(rootReducer)

In the above example, state will look like

{
firstNamedReducer: {},
nestedReducer: {
  reducerA: {},
  reducerB: {},
  reducerC: {},
secondNamedReducer: {}
}

Challenges In real applications we have deep nested messed up structure like this

todoActivity: {
  documents: {...},
  newActivity: {...},
  selectedTab: "TODO",
  selectedActivities: [{}, {}],
  .
  .
  .
}

This cannot be clubbed under "todoActivity" key as a combinereducers in cleaner way. The todoActivity is having more than 15 keys already, many of them are deeply nested. So, I think, I can create separate reducer for "documents" and rest of the keys can stay inside this object (reducer) only.
But how???

export default newCleanerReducer(state, action) => ({
  ...todoActivityReducer(state, action),
  documents: documentReducer(_.get(state, 'documents', undefined), action),
});

As you can see, my all clutter related to documentReducer can be moved to a separate files with it's own types, action and reducer files. I can also adhere to Seperation of Concern here

Top comments (0)