Why I don’t like ImmutableJS in React

March 21, 2018 0 Comments

Why I don’t like ImmutableJS in React

 

 

Click here to share this article on LinkedIn »

I don’t think I need to preach to the choir of how evil mutation is in javascript applications, and how ImmutableJS helps in eliminating it by wrapping data into objects with private properties.

It is a very brilliant idea, indeed. It forces you not being able to mutate anything, in the whole app!

I like it personally. However, when it comes to React, I found it is a bit (or very) unnecessary. How so? Let’s begin with what problems does ImmutableJS try to resolve.

As single source of truth is the bible in JS, allowing to change values could be disastrous. For example, I have a list of clients data requested from server, and I pass it to two components. Component A changes it, but component B doesn’t know about it. What’s worse, the original client list is gone, for ever, until you reset it with another remote request.

How ImmutableJS does is wrap (or encapsulate) everything into it’s own Map, or object, like Java. Plus, it makes all properties private, and only provides getters and setters. What’s so good is, setters don’t set, they return a brand new object with the new value you want! So basically you can’t change any value of the original object once it’s wrapped by ImmutableJS.

All you are dealing with in React are props and state. Let’s have a quick recap.

props: Read only, passed from the parent. Even you can assign a different value to a prop, it doesn’t change the view, it does nothing. This is very important.

state: Local variables, or I should call it, constants. The reason is, assigning value to the state doesn’t mean anything either. It doesn’t update the view, and the value is only changed locally to your scope (within the function you update it).

OKay, if you still guessing what I am trying to say, then you’d probably keep reading.

As a experienced React Developer, I’ve never used, or seen assigning values to props, or state, except for some experiments. If you are doing it, STOP, before you get caught! Although, I truly believe, every React developer would stop doing it very soon enough in their React journey, or the journey itself.

That comes to my point of view: you never assign value to props or state in React, only which that matters.

What about the other variables you create outside of the lifecycle?

My question right back to you: do they matter?

I’m afraid not. If you try to use a variable to update the view, instead of those two cases, you will struggle, and eventually get frustrated. Otherwise, you are not using React’s feature.

Despite that React doesn’t have constraints on assigning value to props or state, you will not like to do it, you will not want to do it, and you will not do it.

React itself is functional. How so?

Every React component is actually a function. Props and state are wrapped inside. If you want to change a parent’s state from a child, they only way is to use a function (and of course, you are setting a new state).

But ImmutableJS provides fully functional APIs.

I completely agree, and that’s what you should be doing as well. There are a lot of libraries that can help you. I would recommend RamdaJS.

It provides more functions than you can expect, and they are all pure functional. You can do currying, composition, functors and many many exciting features. Watch the video below if you want more details.

Yes, you have to use another library in your code, like that there are too many libraries you are using. But that’s the only downside, my friend. And I won’t call it a con to be honest.

I’ve read some articles about how well ImmutableJS works with Redux.

I’m not saying it is not, but really, do you need to?

Reducers in Redux are completely functional as well. Reducers always return a new state. You might want to use ImmutableJS only inside reducers, to avoid mutating the state that is passed in. But for the state that it returns, do you really need to make it an Immutable object? The answer is mentioned above.

With ImmutableJS, I have to click and click and click to expand the wrapped data in the console. If it is just a simple nested list of objects, I can’t simply find out what’s inside.

There are some devtools you can use to help you bring the data back to normal state though, I still don’t like the feeling of the unreachable data.

I love the features of ES6. Using ImmutableJS is kind of a bummer. Instead of using partial assignment, you need to always call get.

// ES6
const {profile, image, age, gender} = this.props.client;
// ImmutableJS
const profile = Immutable.get(this.props.client, 'profile');
const image = Immutable.get(this.props.client, 'image');
const age = Immutable.get(this.props.client, 'age');
const gender = Immutable.get(this.props.client, 'gender');

and Spread Operator:

// Spread operator
return {
...state,
profile: R.map(mapClientToProfile, state.client),
updated: true,
someOtherValue: value
}
// ImmutableJS
return merge(state, {
profile: ImmutableJS.get(state, 'client').map(mapClientToProfile),
updated: true,
someOtherValue: value
})

Some argue that performance of using spread operator is not as efficient as merge function (run some tests here). And syntax wise, there is not much different between spread operator and calling a function, so function wins this point. As you can see, ImmutableJS is trying to move to functional, however, it is still not quite right. (Watch the video above, it really explains it!)

To sum up, in React, the mechanism of updating view is well designed for you to start to learn how to avoid making direct mutation and do things more functional, and ES6 provides very nice features to help you forget about mutation as well.

Changing to pure functions is another way to avoid mutation in your code, one good tool is RamdaJS. ImmutableJS also provides some functions like map, filter and find, but very commonly, people unwrap an Immutable object, do the complex mapping and wrap it back again. Why bother wrapping them at the first place? It adds levels of complexity to your data, instead of simplifying.

To me, if you really understand how bad mutation is, and willingly use libraries to avoid it, ImmutableJS is just one of the options, and definitely not the best. Some people use it to prevent other developers from doing wrong stuff, which is understandable, but you know, there are always more friendly ways.


Tag cloud