DEV Community

Cover image for Immer vs Ramda - two approaches towards writing Redux reducers

Immer vs Ramda - two approaches towards writing Redux reducers

Franciszek Krasnowski on February 20, 2021

Reducers - a core element of Redux's philosophy that tightly grabs mutations of a given state in one place. In theory, the pure nature of reducers ...
Collapse
markerikson profile image
Mark Erikson

Note that you should be using our official Redux Toolkit package, which already comes with Immer built in:

redux.js.org/tutorials/fundamental...

In addition, createSlice also generates your action creators for free and handles all the TS typing based on the payload types that you declare.

Collapse
fkrasnowski profile image
Franciszek Krasnowski Author

I am aware of Redux Toolkit. (I probably should mention that library in the article). However, this article is about the comparison of approaches to writing reducers, and the problems I've mentioned are not limited to Redux so it's not targeting mainly Redux, but Immer and Ramda as well. I've considered Redux as a good foundation for further analysis of those libraries and something that many devs can relate to. I like the way Redux Toolkit implements Redux, Immer, Redux Thunk and automatic action creators. I'm also open to other implementations for example: redux-observable + Ramda.

Collapse
markerikson profile image
Mark Erikson

As it turns out, you can use Redux Toolkit even if you're not using a Redux store!

A reducer is, ultimately, just a function. It doesn't matter if that function is implemented using vanilla JS, Immer, Ramda, Lodash/FP, or something else.

I've used Redux Toolkit's createSlice API multiple times to create reducers that were only meant for use with the useReducer hook in a React component, in apps that weren't using a Redux store at all.

If you're looking at using Immer to write a reducer, you should seriously consider just using createSlice instead of calling produce yourself. createSlice adds minimal extra runtime overhead beyond Immer by itself, and works great with TypeScript as well.

Thread Thread
fkrasnowski profile image
Franciszek Krasnowski Author

Yeah, it's a great tool indeed. I've included your thoughts in the article

Collapse
webduvet profile image
webduvet

IMHO redux-toolkit is almost equally ugly as immer. It does not bring anything to the table except extra layering.

Collapse
chasm profile image
Charles F. Munat

The problem with Immer is that it purports to give you the benefits of functional programming without having to learn functional programming. You can keep using all your old, impure, mutable techniques, but Immer will babysit for you and clean up your messes. This is infantilizing.

I much prefer Ramda because it means that I have to think like a functional programmer -- something that is much easier than most OOP programmers believe. If they hadn't learned OOP first, they wouldn't have so much trouble learning FP. It requires a lot of unlearning.

But when I teach beginners, I always start with FP and only FP, and I often use Ramda. Then I have them reimplement the Ramda functions in vanilla JS -- it's not difficult at all. In the end, they understand immutability, referential transparency, recursion, and more and it just comes naturally to them.

For me, Immer is a code stink.

Collapse
fkrasnowski profile image
Franciszek Krasnowski Author

The problem with Immer is that it purports to give you the benefits of functional programming without having to learn functional programming

Most software developers are lazy. It's easier to just upgrade your existing tool a little to fix some problems than to learn the new ecosystem in which this problem does not exist. You can make great language but most devs who know C will choose C++.

If it comes to me I like how it's done in Rust where you can create mutable references inside a function. In JavaScript similar functionality can be achieved by just making deep copies inside the function:

const fn = arr => {
   let nextArr = deepCopy(arr)
   nextArr[1] = 2
   return nextArr
}
Enter fullscreen mode Exit fullscreen mode

Still Immer makes it terser:

const fn = produce(arr => {
   arr[1] = 2
})
Enter fullscreen mode Exit fullscreen mode

I like the explicitness of this "mutation". Immer can be handy when you have to deal with some stateful problems - it encapsulates your mutating logic. And that's what most functional languages do - hiding state from a developer by for example switching tail recursion to iteration.

Collapse
redbar0n profile image
Magne • Edited on

If you are using TypeScript (which you should), then instead of Ramda, I recommend now using ts-belt instead.

ts-belt is a recent "Fast, modern, and practical utility library for #FP in #TypeScript."

ts-belt is an alternative to lodash, ramda, rambda, rameda.

Look and feel:
mobily.github.io/ts-belt/docs/gett...

Benchmarks:
mobily.github.io/ts-belt/benchmark...

NPM & GitHub stats:
moiva.io/?npm=@mobily/ts-belt+loda...

Collapse
antonmelnyk profile image
Anton Melnyk • Edited on

Nice article. For me, Ramda is an obvious choice. Immer destroys the whole purpose of Redux and the functional way to handle data logic. It makes simple immutability and "todo"-like reducers look easy, but for complex applications where Redux shines, it won't bring that much benefit. Moreover, the explicitness and clean code is the point of FP - Immer hides it underneath, covering what is actually happening in reducers.

Ramda is a much more scalable and clean support library for Redux and is a bummer Immer is perceived as default approach in Redux toolkit. Ramda embraces FP - Immer tries to hide it under the cover.

Collapse
fkrasnowski profile image
Franciszek Krasnowski Author

I’ve got similar impressions. Immer is enjoyable if it comes to simple reducers managing some simple/local states; however, Redux is designed to work well with huge apps, where state and its mutations can be very hard to track. Still, many devs use Redux with simple apps. I think Redux Toolkit aims to reduce this gap between use cases and make Redux approachable in those simple scenarios

Collapse
xavierbrinonecs profile image
Xavier Brinon

This whole approach should be based on complexity and how to fight it. State management is one axis of evil; it is difficult to keep simple.

There is an excellent paper about complexity in programs as the root of all evil, available for free: Out of the tarpit.

Immer will not get you very far against complexity as compared to Ramda or even ADT libraries like Crocks (crocks.dev/)

Also shout out for taking advantage of the ASI feature, those pesky semicolons...

Collapse
kontsedal profile image
Bohdan

Can't imagine choosing ramda over immer in this case :)

Collapse
neoroma profile image
Роман Ш

Damn, so many bold words

Collapse
fkrasnowski profile image
Franciszek Krasnowski Author

As always. Thanks