Web front-end
9 minute read

React, Redux and Immutable.js: Ingredients for Efficient Web Applications

Ivan first started coding back in 2007 at the beginning of his college education, and he became really passionate about it.

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 and 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.

React, Redux and Immutable.js: Ingredients for Performant Web Applications

In this Immutable.js tutorial, we will build a simple app using React and Redux, 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).

const obj1 = { prop: ’someValue’ };
const obj2 = { prop: ’someValue’ };
console.log(obj1 === obj2);   // false

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.

Immutable.js tutorial references illustrated

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.

import { Map } from ‘immutable’;

//  transform object into immutable map
let obj1 = Map({ prop: ’someValue’ });  
const obj2 = obj1;
console.log(obj1 === obj2);  // true

obj1 = obj1.set(‘prop’, ’someValue’);  // set same old value
console.log(obj1 === obj2);  // true | does not break reference because nothing has changed 

obj1 = obj1.set(‘prop’, ’someNewValue’);   // set new value
console.log(obj1 === obj2);  // false | breaks reference 

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 Examples

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?

React, Redux and Immutable.js illustrated

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.

Our reducer will consist of 2 small parts:

  • todoList
  • activeFilter
// reducers/todos.js
import * as types from 'constants/ActionTypes';
// we can look at List/Map as immutable representation of JS Array/Object
import { List, Map } from 'immutable';  
import { combineReducers } from 'redux';  

function todoList(state = List(), action) {  // default state is empty List()
  switch (action.type) {
  case types.ADD_TODO:
    return state.push(Map({   // Every switch/case must always return either immutable 
      id: action.id,          //  or primitive (like in activeFilter) state data  
      text: action.text,      //  We let Immutable decide if data has changed or not
      isCompleted: false,

  // other cases...

    return state;

function activeFilter(state = 'all', action) {
  switch (action.type) {
  case types.CHANGE_FILTER:
    return action.filter;  // This is primitive data so there’s no need to worry

    return state;

// combineReducers combines reducers into a single object
// it lets us create any number or combination of reducers to fit our case
export default combineReducers({

Connecting with Redux

Now that we have set up a Redux reducer with Immutable.js data, let’s connect it with React component to pass the data in.

// components/App.js
import { connect } from 'react-redux';
// ….component code
const mapStateToProps = state => ({ 
    activeFilter: state.todos.activeFilter,
    todoList: state.todos.todoList,

export default connect(mapStateToProps)(App);

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:

$ npm install react-pure-render
import shallowEqual from 'react-pure-render/shallowEqual';

shouldComponentUpdate(nextProps, nextState) {
  return !shallowEqual(this.props, nextProps) || !shallowEqual(this.state, nextState);

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.

Extract shouldComponentUpdate into a special separate component:

// components/PureComponent.js
import React from 'react';
import shallowEqual from 'react-pure-render/shallowEqual';

export default class PureComponent extends React.Component {
  shouldComponentUpdate(nextProps, nextState) {
    return !shallowEqual(this.props, nextProps) || !shallowEqual(this.state, nextState);

Then just extend any component in which this shouldComponentUpdate logic is desired:

// components/Todo.js
export default class Todo extends PureComponent  {
  // Component code

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:

  • use ES6 arrow function binding: <Component onClick={() => this.handleClick()} />
  • use bind: <Component onClick={this.handleClick.bind(this)} />

Both approaches will cause Component to re-render because different reference has been passed to onClick every time.

To work around this problem we can pre-bind functions in constructor method like so:

  constructor() {
    this.handleClick = this.handleClick.bind(this);
 // Then simply pass the function
  render() {
    return <Component onClick={this.handleClick} />

If you find yourself pre-binding multiple functions most of the time, we can export and reuse small helper function:

// utils/bind-functions.js
export default function bindFunctions(functions) {
  functions.forEach(f => this[f] = this[f].bind(this));
// some component
  constructor() {
    bindFunctions.call(this, ['handleClick']);   // Second argument is array of function names

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:

  id: 1,
  text: 'todo1',
  isCompleted: false,
}, {
  id: 2,
  text: 'todo2',
  isCompleted: false,

Immutable.js API is very similar to regular JavaScript, so we would use todoList like any other array of objects. Map function proves best in most cases.

Inside a map callback we get todo, which is an object still in immutable form and we can safely pass it in Todo component.

// components/TodoList.js
render() {
   return (
      // ….
            {todoList.map(todo => {
              return (
                <Todo key={todo.get('id')}
      //  ….

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


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


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:

// components/Todo.js
render() {
  const { id, text, isCompleted } = this.props.todo.toObject();
  // …..

Let’s See It All in Action

In case you have not cloned the code from GitHub yet, now is a great time to do it:

git clone https://github.com/rogic89/ToDo-react-redux-immutable.git
cd ToDo-react-redux-immutable

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

npm install
npm start

Immutable.js example

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. This means Immutable.js performance tends to be good in most scenarios.

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

Understanding the basics

What is Redux?
Redux is an open-source JavaScript predictable state container. Redux is typically used to create user interfaces, in conjunction with libraries such as React or Angular.
What is Immutable.js?
Immutable.js is a library designed for the creation of immutable collections of data. It is commonly used in React/Redux development. Immutable.js was created by Facebook.
What does immutable mean?
Objects that can’t be modified after creation are considered immutable objects, as their state and properties cannot be modified once they are instantiated. This is in contrast to mutable objects which, as their name suggests, can be changed.


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....
Sergii Demianchuk
Concise, and gives fresh information to think of. 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?
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
Kabir Baidya
Great Post. Pretty well explained
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 lodash.
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!
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?
great article! thx for sharing your experience
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?
It was double spread, this part, [...base, ...args] FYI now supported by node v6 :)
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).
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.
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.
Great article, it helped me to understand better how react handles diffing of immutable objects. Thank you!
Ivan Rogić
Yep, you are right, also a great way to do it.
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ć
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.
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.
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 <a href="https://github.com/rogic89/ToDo-react-redux-immutable/issues/2">this github issue</a>. TL;DR use an older version of node (4.4.7 works)
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)
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.
Taylor Mitchell St Joseph
I agree. At the moment I am converting my Immutable objects to JS objects in my Redux mapStateToProps() function, thus passing a standard javascript object to my components. This is good, as there is no ImmutableJS api code baked into my components. HOWEVER, I have multiple reducer properties in my mapStateToProps function, so when 1 reducer's state updates, ALL all other reducer props end up being converted toJS(), which assigns them a new reference and any shallow comparisons will now return false. I still have the benefit of an Immutable app that I can step through (with a tool like Redux DevTools), but I lose some performance benefits as my components will re-render when they don't need to. At the moment it's not a problem as the app is small, but it's something to keep an eye on as it scales. I wonder if there is a sweet spot between Immutability and keeping components clean of Immutable's API...
luan au
Do you not then have to maintain this var in every component?
No, it could be easily done in the store itself of whatever flux system you're using. So there would only need be one place. I've done dirty/clean rendering systems long before immutable, react, or flux in general, and I've applied the concept to react/flux as well. It works very well and is extremely easy to do. Because of this I find very little need for the overhead of immutable.js.
J. Erickson
Cool !
Good article on React, Redux and Immutable.js. Thanks, Akash www.digifutura.com
Ivan, your bio has a typo in it.
Free Coupon Hub
The complete React and Redux course: Build modern apps https://couponhub4u.blogspot.com/2017/08/the-complete-react-and-redux-course.html
Hello Ivan and thanks for the article. I have a question that I can't find an answer for. I have an app with an array of objects and the idea is to filter using a text input. I've seen some code putting the filtering logic in mapStateToProps in order to pass a filtered list of items to the component. I've seen other code filtering in the reducer, while storing the filter string in the reducer. My confusion comes from the fact that the filtering is just returning a smaller set of data, nothing more. The idea of the filter is not to change or update the array, just show a limited amount of items. The data will be updated by other parts of the code, so I'm more inclined to filter in mapStateToProps in order to pass the filtered data without changing the original in the store. Any help will be more than welcome. Best, Rodrigo.
Ivan Rogić
It would be best to just pass entire array via mapStateToProps and then handle the input onChange to array.filter() directly inside that component. That way only that component would be required to re-render and that is the simplest solution. Filter function does not mutate the original array from the store so you are good to go.
Thank you Ivan!!!
comments powered by Disqus