A small trick to write clean reducers

10,692 reads

@ maxired Maxence Software developer building awesome products

Writing react-redux reducers might be sometimes painful. Specifically, you might have to write lots of boilerplate code just to change one value or flag in a nested object. We will see how a small trick can help us reduce this code.

TLDR: you can use lodash/fp/set to modify a deep attribute in your store in an immutable way. for example with import set from 'lodash/fp/set' and then use set(path,value, state) such as with set(`manufacturers.${manufacturer}.models.${model}.options.colors.${color}`, true)(state)

Current Situation

When you are writing react-redux reducers, you must be careful about not mutating objects in the store. This is not 100% true in a simple react application, but since you are probably using some shallow comparison of props somewhere in your apps, this is true. This is the case if you use come kind of PureComponent, or using react-redux connect with mapStateToProps functions, or any other way where you could use reselect plugged to your store. If your are not, you probably should.

Some people love to use Immutable.js object in their store. If that’s your case and are happy with it, then you don’t really need to go further in the article. Personally, I prefer to deal with regular JS object in my store. I indeed found doing conversion between plan object JS object and Immutable to be cumbersome.

So, in order to write my reducers so they won’t mutate object in the store, and using regular JS object, here how I used to write my reducers.

You can probably find other ways to write this in a way you like better, or even argue that the shape of my redux store could be changed to better suit this operation, but still, there is time when you have to modify a deep attribute in your store.

I guess at this point you understand why I wanted to get a better solution. I will present one, but if you have other options, I will be happy to see it in comments ;)

Finding a solution

Now that our problem is correctly stated, as a good lazy programmer that you probably are, you must be wondering if there is a solution to this specific need. There is none as far I know. Again, feel free to correct me, or create one based on this article. Actually, the last section should be also interesting for you in that case.

Long story short, I’ve been looking for a solution to this problem, and since people I work with are terrible fans of lodash, I thought there might be a solution here. I already knew the set method, which is useful to set the value of attributes in nested objects. The problem with the regular version of the set method, is that it will mutate the object on which we set the attribute. As we said in introduction, this is not something that we want here. Basically what I was looking for was an immutable version of set.

I am glad I was not the only one.

The first result of this quick search was the trace to follow

As you can see on the above screenshot, my now hero Rico Sta. Cruz, asked this question as a lodash issue two years ago. John-David Dalton answered immediately that it will come in lodash/fp, and Kyle Kelley confirmed that more recently, even giving the syntax that we could use for “Redux style state setting”

After that, I wanted to check if this solution was used and recommended in the react community. I did a very quick check, but did not found much reference to it. Nevertheless, I found one example, written by the now famous Dan Abramov in this stackoverflow post.

Extract from Dan Abramov post on stackoverflow, available as gist here

I think that we now have our answer: you can use lodash/fp/set function as an helper in a react-redux reducer in order to avoid useless code. This is even done by someone from the community whose talent is recognized by lots.

Going further ?

I won’t detail much here how you can use set to modify an object inside an array. In fact, it is already done in the previous sample. If you want modify several properties in the same time, I believe you can also use lodash/fp/merge or lodash/fp/defaultsDeep to do so.

Also, I told you previously that lodash/fp/set was able to modify object in an immutable way. This the case. What you also want be sure, is that it will copy only objects that are needed, but will keep references for objects which are not impacted. This is also the case: you are safe, using lodash/fp/set will not lead to useless rendering.

Another topic which is useful to highlight here is performance. Overall, lodash has great performances. Nevertheless, If this is a really important matter to you, I believe there are way to be faster that lodash here. The immutability around lodash/fp is done as a layer around the initial implementation of lodash methods, here lodash set.This lead to the object traversal being done more than one time: the run-time complexity is bigger than it needs to be. Actually, I created a minimalist implementation of such an immutable set function that will work with only one iteration

I compared this implementation to lodash/fp/set, and despite being very naive, it seems to outperform it, if I believe this jsPerf test.

jsPerf results of lodash/fp/set vs the naive implementation shown previously, transpiled with babel

This make me think that there is a room for creating a library dedicated to this use case and more. The closest I found so far is reduceless, which is more a wrapper around the store so you don’t have to write reducer, but for different reasons, I would not recommend it.

Share this story @ maxired Maxence Read my stories Software developer building awesome products

Tags