Immutability in Javascript & React

React is a famous library for building dynamic user interfaces. Data immutability is an idea that came from functional programming and applying it to design of your front end app can have many benefits.

What is Data mutation? 
To understand the idea of data mutation, will need to step back to the foundations of programming and understand how we can compare data structures in javascript. Comparing primitive types is pretty easy.

let num1 = 10,
    num2 = 10;
num1 === num2; // true

It is different in case of non-primitive data types.

let obj1 = { name: "Pragati", lname: "Garud" },
    obj2 = { name: "Pragati", lname: "Garud" };
obj1 === obj2; // false

But they look same. Why are they not equal? 🙃
For above objects, they are same in terms of keys and values but as they are initialized separately, they are not same in terms of reference. The result would have been different if they would have been pointing to same address.

let obj1 = { name: "Pragati", lname: "Garud" },
    obj2 = obj1;
obj1 === obj2; // true

This has one consequence though.

obj1.name = "unknown";
console.log(obj1.name); // unknown
console.log(obj2.name); // unknown

In above snippet, we have assigned unknown to name key of obj1. But as obj1 and obj2 are pointing to same reference, change is visible in both variables. Every complex data structure(array/object) in javascript follows the same principles of reference equality.

In short, For non-primitive cases == and === operators compare variables by their reference. we can compare them by values as well, but in a complex data structure, this will need multiple equality checks which are called deep equality checks.

let obj1 = { name: "Pragati", lname: "Garud" },
    obj2 = { name: "Pragati", lname: "Garud" };
valueCompare(obj1, obj2); //true

Implementing such equality would be harder with nested data structures.

// Input: obj1 and obj2
// Output: true if obj1 is equal to obj2 in terms of values
function valueCompare(obj1, obj2) {
   const keys1 = list of keys of obj1;
   const keys2 = list of keys of obj2;
   if (keys1.lenth !== keys2.length) return false;
   for each key in keys1: 
      if (key is not present in keys2) 
         return false;
      if (typeOf(keys1[key] != typeOf(keys2[key]))
         return false;
      if (keys1[key] is a primitive && keys1[key] !== keys2[key])
         return false;
      if (obj1[key] is non primitive):
         isEqual = valueCompare(obj1[key], obj2[key]);
         if(!isEqual) return false;
}

Get Rid of Mutations:
Just don’t mutate objects, instead, create a changed copy of it. 
You can achieve that using following ways:

1] Object.assign: You can use Object.assign function to create a copy.

let obj3 = Object.assign({}, obj1, { name: "unknown" });
obj3 === obj1; //false

In this way, every time you mutate an object, it gets a new reference.

2] [].concat(): You can use [].concat() for changing array values in an immutable way.

let numbers = [10, 20, 30];
numbers[1] = 22; // This will not change reference to an array
// Instead what you can do copy list and perform update as below
let numbers = [10, 20, 30];
let changedNumbers = [].concat(numbers);
changedNumbers[1] = 22;
changedNumbers === numbers; // false

What it has to do with React? 
React components have state, When you call setState function, component re-renders. React can’t assume anything about state, you can mutate however if you want. That’s why setting state always re-renders component, even if state value is not changed.

It’s hard to check whether your state has changed or not if your state is complicated (contains nested object). You need to make deep equality check because when objects are compared using reference equality, you can’t be sure whether next state is changed, and deep equality check will take more time as compared to re-render time. So React prefers to re-render component on every setState call instead of state change comparison.

Thanks! I hope this article helpful for you 🙂

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.