This post is part of a series about React, Redux, Immutable.js and Flow

Two of the three Redux principles are “State is read-only” and “Changes are made with pure functions”. When changing the read-only state, you are not allowed to mutate the existing object: You are supposed to create a new object.

But this new object can share the parts that have not changed with the previous state.

Writing that code to update the read-only state is definitely possible with just plain JavaScript objects and arrays. But it is easier when you have immutable data structures. In this aritcle, I want to write about the basics of immutable data structures. So that, in the next post, I can show you how to use them with Redux.

Immutable.js

immutable.js gives you several immutable data structures: Map, List, Set, Record and more. Those data structures cannot be changed once created.

Convert from / to JavaScript

You can create those data structures with their constructors, which also accept JavaScript objects and arrays to initialize the data structure from.

import { Map, List } from 'immutable'

const emptyMap =  new Map();
const emptyList = new List();
const initializedMap =  Map({ x: 1, y: 2});
const initializedList = List([1, 2, 3]);

If you want to deeply convert some JavaScript data structure to nested immutable data structures, you can use fromJS. You can convert back to plain JavaScript data using toJS.

import { fromJS } from 'immutable'
const originalJS = {
    x: 'a',
    y: 'b',
    z: [1, 2, 3]
};
const immutable = fromJS(originalJS);
const convertedBack = immutable.toJS();

But, when working with immutable.js, you will rarely ever convert from or to JavaScript. Most of the time, you should work with the immutable data structures themselves (getting values and performing immutable updates). Only when you pass data from or to the outside of your own system, you would convert from JavaScript and back.

Query Functions

You can use get to get some value from the immutable data structure, and getIn to get a deeply nested value. Using the immutable object from above, this is how it works:

const a = immutable.get('x');        //returns 'a'
const b = immutable.getIn(['z', 1]); //returns 2

You can also run other functions that you would expect to work on collections, like forEach, filter, map, reduce and others.

Immutable Updates

OK, and now comes the interesting part. You can update those immutable data structures, but that will not modify them. Whenever you “update” one of these data structures, you get back a new object, and you can think of it as a complete copy of the old one, with the updated value modified (this is not how it works internally, see below).

const im = fromJS({ a: 1 });
console.log(im.get('a')); //prints 1

im.set('a', 2);
console.log(im.get('a')); //prints 1! Original data structure unchanged!

const im2 = im.set('a', 2);
console.log(im2.get('a')); //prints 2

When you need the previous value to calculate the new value of a field, you can use update, which takes a function as an argument that calculated the new value based on the old value.

const im = fromJS({ a: 1 });
const im2 = im.update('a', oldA => oldA+2);
console.log(im2.get('a')); //prints 3

And if you want to set or update deeply nested values, you can use setIn and updateIn.

const im = fromJS({ nested: { x: 1 }});
const im2 = im.updateIn(['nested', 'x'], oldX => oldX+2);
console.log(im2.getIn(['nested', 'x'])); //prints 3

And this Performs Well?

Yes. The immutable data structures try to copy as little as possible when doing mutable updates. They are implemented as trees that can share all the stuff that has not changed.

But, immutable data structures are slightly slower than using mutable JavaScript data structures. Just a few weeks ago, I was debugging a performance problem for a client. Updating their React/Redux app was too slow in some use cases. They were accessing immutable data structures a lot in their mapStateToProps.

As an experiment, I changed all those immutable data structures to JavaScript objects and arrays. Updates were slightly faster (~20%), but still not fast enough. Immutable.js was not our main performance bottleneck (and I think not even the second smallest bottleneck), so I put it back in. (I will write more about performance in later posts).

In exchange for that slight slowdown, you get a lot of safety. When you have immutable data, you can be sure it is unchanged, even when time has passed. And there are also some potential speed-ups: You never have to deeply compare data structures. If it is still the same object (pointer), the data is un-changed.

To Recap…

Immutable data structures can help you add safety to your programs. And when you use Redux, writing your reducers correctly will be easier and less error-prone when you use them.

But they are slightly slower than normal JavaScript data structures in some cases.

Also, this blog post was only a very quick overview of immutable.js and what you can do with it. If you want to learn more, check out the official site.