React, Redux and Immutable.js are currently among the most popular JavaScript libraries and are rapidly becoming developers’ first choice when it comes to front-end development. In the few React/Redux projects that I have worked on, I realised that a lot of developers getting started with React do not fully understand React and how to write efficient code to utilise its full potential.

In this article we will build a simple app using React, Redux and Immutable.js, and identify some of the most common misuses of React and ways to avoid them.

Data Reference Problem

React is all about performance. It was built from the ground up to be extremely performant, only re-rendering minimal parts of DOM to satisfy new data changes. Any React app should mostly consist of small simple (or stateless function) components. They are simple to reason about and most of them can have shouldComponentUpdate function returning false.

shouldComponentUpdate(nextProps, nextState) {
return false;
}

Performance wise, the most important component lifecycle function is shouldComponentUpdate and if possible it should always return false. This ensures that this component will never re-render (except the initial render) effectively making the React app feel extremely fast.

When that is not the case, our goal is to make a cheap equality check of old props/state vs new props/state and skip re-rendering if the data is unchanged.

Let’s take a step back for a second and review how JavaScript performs equality checks for different data types.

Equality check for primitive data types like boolean, string and integer is very simple since they are always compared by their actual value:

1 === 1
’string’ === ’string’
true === true

On the other hand, equality check for complex types like objects, arrays and_functions_ is completely different. Two objects are the same if they have the same reference (pointing to the same object in memory).

Even though obj1 and obj2 appear to be the same, their reference is different. Since they are different, comparing them naively within the shouldComponentUpdate function will cause our component re-render needlessly.

The important thing to note is that the data coming from Redux reducers, if not set up correctly, will always be served with different reference which will cause component to re-render every time.

This is a core problem in our quest to avoid component re-rendering.

Handling References

Let’s take an example in which we have deeply nested objects and we want to compare it to its previous version. We could recursively loop through nested object props and compare each one, but obviously that would be extremely expensive and is out of the question.

That leaves us with only one solution, and that is to check the reference, but new problems emerge quickly:

Preserving the reference if nothing has changed

Changing reference if any of the nested object/array prop values changed

This is not an easy task if we want to do it in a nice, clean, and performance optimised way. Facebook realised this problem a long time ago and called Immutable.js to the rescue.

None of the Immutable.js functions perform direct mutation on the given data. Instead, data is cloned internally, mutated and if there were any changes new reference is returned. Otherwise it returns the initial reference. New reference must be set explicitly, like obj1 = obj1.set(...);.

React, Redux and Immutable.js

The best way to demonstrate the power of these libraries is to build a simple app. And what can be simpler than a todo app?

For brevity, in this article, we will only walk through the parts of the app that are critical to these concepts. The entire source code of the app code can be found on GitHub.

When the app is started you will notice that calls to console.log are conveniently placed in key areas to clearly show the amount of DOM re-render, which is minimal.

Like any other todo app, we want to show a list of todo items. When the user clicks on a todo item we will mark it as completed. Also we need a small input field on top to add new todos and on the bottom 3 filters which will allow the user to toggle between:

All

Completed

Active

Redux Reducer

All data in Redux application lives inside a single store object and we can look at the reducers as just a convenient way of splitting the store into smaller pieces that are easier to reason about. Since reducer is also a function, it too can be split into even smaller parts.

In a perfect world, connect should be performed only on top level route components, extracting the data in mapStateToProps and the rest is basic React passing props to children. On large scale applications it tends to get hard to keep track of all the connections so we want to keep them to a minimum.

It is very important to note that state.todos is a regular JavaScript object returned from Redux combineReducers function (todos being the name of the reducer), but state.todos.todoList is an Immutable List and it is critical that it stays in such a form until it passes shouldComponentUpdate check.

Avoiding Component Re-render

Before we dig deeper, it is important to understand what type of data must be served to the component:

Primitive types of any kind

Object/array only in immutable form

Having these types of data allows us to shallowly compare the props that come into React components.

Next example shows how to diff the props in the simplest way possible:

Function shallowEqual will check the props/state diff only 1 level deep. It works extremely fast and is in perfect synergy with our immutable data. Having to write this shouldComponentUpdate in every component would be very inconvenient, but fortunately there is a simple solution.

This is a very clean and efficient way of avoiding component re-render in most cases, and later if the app gets more complex and suddenly requires custom solution it can be changed easily.

There is a slight problem when using PureComponent while passing functions as props. Since React, with ES6 class, does not automatically bind this to functions we have to do it manually. We can achieve this by doing one of the following:

If none of the solutions work for you, you can always write shouldComponentUpdate conditions manually.

Handling Immutable Data Inside a Component

With the current immutable data setup, re-render has been avoided and we are left with immutable data inside a component’s props. There are number of ways to use this immutable data, but the most common mistake is to convert the data right away into plain JS using immutable toJS function.

Using toJS to deeply convert immutable data into plain JS negates the whole purpose of avoiding re-rendering because as expected, it is very slow and as such should be avoided.
So how do we handle immutable data?

It needs to be used as is, that’s why Immutable API provides a wide variety of functions, map and get being most commonly used inside React component.
todoList data structure coming from the Redux Reducer is an array of objects in immutable form, each object representing a single todo item:

If you plan on performing multiple chained iterations over immutable data like:

myMap.filter(somePred).sort(someComp)

… then it is very important to first convert it into Seq using toSeq and after iterations turn it back to desired form like:

myMap.toSeq().filter(somePred).sort(someComp).toOrderedMap()

Since Immutable.js never directly mutates given data, it always needs to make another copy of it, performing multiple iterations like this can be very expensive. Seq is lazy immutable sequence of data, meaning it will perform as few operations as possible to do its task while skipping creation of intermediate copies. Seq was built to be used this way.

Inside Todo component use get or getIn to get the props.

Simple enough right?

Well, what I realized is that a lot of the time it can get very unreadable having a large number of get() and especially getIn(). So I decided to find a sweet-spot between performance and readability and after some simple experiments I found out that Immutable.js toObject and toArray functions work very well.

These functions shallowly convert (1 level deep) Immutable.js objects/arrays into plain JavaScript objects/arrays. If we have any data deeply nested inside, they will remain in immutable form ready to be passed to components children and that is exactly what we need.

It is slower than get() just by a negligible margin, but looks a lot cleaner:

Let’s See It All in Action

Starting the server is as simple (make sure Node.js and NPM are installed) as this:

npm install
npm start

Navigate to http://localhost:3000 in your web browser. With the developer console open, watch the logs as you add a few todo items, mark them as done and change the filter:

Add 5 todo items

Change filter from ‘All’ to ‘Active’ and then back to ‘All’

No todo re-render, just filter change

Mark 2 todo items as completed

Two todos were re-rendered, but only one at a time

Change filter from ‘All’ to ‘Active’ and then back to ‘All’

Only 2 completed todo items were mounted/unmounted

Active ones were not re-rendered

Delete a single todo item from the middle of the list

Only the todo item removed was affected, others were not re-rendered

Wrap Up

The synergy of React, Redux and Immutable.js, when used right, offer some elegant solutions to many performance issues that are often encountered in large web applications. Immutable.js allows us to detect changes in JavaScript objects/arrays without resorting to the inefficiencies of deep equality checks, which in turn allows React to avoid expensive re-render operations when they are not required.

I hope you liked the article and find it useful in your future React endeavours.

About the author

Ivan first started coding back in 2007 at the beginning of his college education, and he became really passionate about it. He likes learning new technologies and staying on top of his game all the time. During his early employment, he learned a lot about the importance of communication between team members and how to be a great team player. [click to continue...]

Comments

Sergii Demianchuk

Concise, and gives fresh information to think of. Thanks!

Michel H.

Nice post! When I started out with React I though of JavaScript as a pure functional language. But what I didn't know was, a lack of lazy evaluation and built-in immutable data prevents JS from becoming a functional language. This is because most interpreters are call-by-name and not call-by-need.
It corrects the flaws of underscore.js, namely that operations of different data structures were forced on JavaScript arrays and objects, mixing the concept of data types, and losing immutability. Long story short, only React made me realize how important Immutable.js really is! So weird....

Ivan Rogić

Well, there is not a lot of use cases for components without any props and state so the answer is no.
Obviously, component with _shouldComponentUpdate_ returning _false_ can't have any state (majority of your components should be stateless), but it can have props, we just want to prevent re-rendering.
Perfect example is the _AddTodo_ component --> https://github.com/rogic89/ToDo-react-redux-immutable/blob/master/src/components/AddTodo.js

Guillaume Claret

Thanks!

Guillaume Claret

Thanks for the post!
Talking about components with:
````
shouldComponentUpdate(nextProps, nextState) {
return false;
}
```
this can only work when there are no props and no state, right?

Kabir Baidya

Great Post. Pretty well explained

Ladi

Brilliant article! Just one question. Is it really necessary to use Immutable.js? According to official documentation reducer function in Redux should always emit a new state object using Object.assign(), so why is there need for such a huge library?

Ivan Rogić

It is not necessary to use Immutable.js, but then you have to be really careful and know exactly how you calculate and return reducer state. Not to mention it looks unreadable and hard to maintain with all pre/post slicing of the arrays --> http://redux.js.org/docs/basics/Reducers.html and these are just simple examples.
Also since ImmutableJS has versatile API, in most cases it removes the need for helper libraries like loadash.

Alexis Mangin

Why does blog articles talking about Redux are always demonstrating "simple" examples? I would love to see hard-core example using Redux, with login and API calls!

BeGe1

So, if I understand this right, immutable.js is solely being used to implement a dirty/clean rendering system to help track when states are updated?
Wouldn't it be many times more efficient just to have a dirty/clean var that is then utilized within the <code>shouldComponentUpdate</code> method and updated wherever you change a state rather than bringing in an entire library to handle it...especially one that is cloning possibly complex objects and returning entire new instances of them each time properties within that data are changed?

jackyon

Hi, I saw the code:
case types.ADD_TODO:
return state.push(Map({
id: action.id,
text: action.text,
isCompleted: false,
}));
and just little curious, I have tested without using "Map", and it is still return the immutable data.
so what's the reason to use "Map" method there?
plz advise, thx!

Jason

Why does this need the --harmony flag to run?
Without it config/index errors on line 63
'var project = (...args) => resolve.apply(resolve, [...base, ...args]);'
I'm struggling to understand why node v5+ doesn't just run this line?

Jason

It was double spread, this part, [...base, ...args] FYI now supported by node v6 :)

eagspoo

Immutable doesn't significantly reduce the overhead of using assign(), nor does it ultimately prevent you from mutating the return value so I have to agree it is kind of pointless. OTOH there are other libraries that achieve the same thing with almost no overhead and actually do prevent you from mutating the returned state afterward. I mentioned one in another comment that I really like, updeep, which not only doesn't constantly get in the way and require you to constantly work around incompatibilities with other libraries that aren't assuming Immutable.js, but it's api for doing deeply nested updates is a real pleasure to use and quite useful even if you didn't care about immutability.

eagspoo

I'm constantly surprised by people promoting immutable.js. In principle using immutable data structures with redux/react is great but immutable is a terrible example of this idea and there are far far better javascript alternatives (updeep being my favorite).

ramusus

Ivan, don't you think declaration of `handleClick` method in ES2016 class in this way more cleaner, then binding them inside constructor?
handleClick = () => {
this....
};
I think so and it gives autobinding to `this` var as well.

Hello, I have a problem npm start works but when opening in browser I have an error "ERROR in ./src/init.js
Module build failed: TypeError: Path must be a string. Received undefined"?

Ivan Rogić

Not really sure what the problem is, but I assume maybe old version of node so webpack doesn't work as it should. Try updating node.

sushill kumar

Awesome blog !!! Just one question you mentioned old version of react in package.json does these matters for application speed?

Ivan Rogić

There's not much to it differently on a bigger app. The only thing I can mention is the API calls with thunk redux middleware and promises, showing loading indication while API call is in progress and a few other things, but I agree, I think that there should be some hard example to show how things work on a larger scale.

Ivan Rogić

Thx!
Well its better to have newest version of React, they are updating it quite frequently, but for this example it's not important, since it was meant to show how to avoid unnecessary re-renders of DOM in React app.

RyanVice

I have to disagree about the complexity that comes with more complex apps. There's a lot of decision points and even simple things like loading data can be confusing and difficult to figure out. How to organize your data model is also not obvious and takes some time to figure out. We've been trying to POC our architecture best practices for a few weeks now and still haven't figured out all the details that would make us comfortable to estimate a larger project.

Henry Baughman

I was having this same issue. It's been addressed in [this github issue](https://github.com/rogic89/ToDo-react-redux-immutable/issues/2). TL;DR use an older version of node (4.4.7 works)

Jack

Why do you use PureComponent for the App component? Connect from react-redux does the same thing, so you're doing shallow comparison twice (inside the Connect component and inside the App component)

Varma

I agree with @disqus_8JE8cX1bdR:disqus, Basically we never need a shallow comparison of props in containers, because connect will take care of that,Only dumb components can have the shouldComponentUpdate hook to do the props comparison

Nissim Levy

Wouldn't it be simpler just to go back to simple web forms with server side events?

Braulio Diez

Using immutablejs is quite tempting, but the main drawback I see is that your components will have to handle immutablejs structures on the UI side, that's something not ideal if we take into consideration separation of concerns, my presentational components shouldn't be aware of that, or e.g. what if I'm using third partie components? I can not force them use immutablejs. Finally you are tied up to immutable at component level as well, on the other hand playing with object.assign and ... on the reducer side maybe is not getting a top notch performance.

Ivan first started coding back in 2007 at the beginning of his college education, and he became really passionate about it. He likes learning new technologies and staying on top of his game all the time. During his early employment, he learned a lot about the importance of communication between team members and how to be a great team player.