Donate to the Palestine's children, safe the people of Gaza.  >>>Donate Link...... Your contribution will help to save the life of Gaza people, who trapped in war conflict & urgently needed food, water, health care and more.

Redux Source Code

Lets look at the Redux Source Code

https://github.com/reduxjs/redux/blob/9d3273846aa8906d38890c410b62fb09a4992018/src/combineReducers.ts#L197

let hasChanged = false
    const nextState: StateFromReducersMapObject<typeof reducers> = {}
    for (let i = 0; i < finalReducerKeys.length; i++) {
      const key = finalReducerKeys[i]
      const reducer = finalReducers[key]
      const previousStateForKey = state[key]
      const nextStateForKey = reducer(previousStateForKey, action)
      if (typeof nextStateForKey === 'undefined') {
        const errorMessage = getUndefinedStateErrorMessage(key, action)
        throw new Error(errorMessage)
      }
      nextState[key] = nextStateForKey
      hasChanged = hasChanged || nextStateForKey !== previousStateForKey
    }
    hasChanged =
      hasChanged || finalReducerKeys.length !== Object.keys(state).length
    return hasChanged ? nextState : state
  }

The line const nextStateForKey = reducer(previousStateForKey, action) >> Redux takes a given state (object) and passes it to each reducer in a loop. And it expects a brand new object from the reducer if there are any changes. And it also expects to get the old object back if there are no changes.

The line hasChanged = hasChanged || nextStateForKey !== previousStateForKey >> Redux simply checks whether the old object is the same as the new object by comparing the memory locations of the two objects. NOT BY DEEP-COMPARING THE PROPS – So if you mutate the old object’s property inside a reducer, the “new state” and the “old state” will both point to the same object. Hence Redux thinks nothing has changed! So this won’t work.

But, it still doesn’t answer some key questions like:

Why is Redux designed like this? Why can’t Redux just make a copy of the old state some place else, then compare object props from reducers? Why is Redux putting this burden on individual developers?

The answer: there is only one way to know if two JavaScript objects have the same properties. To deep-compare them.

But this becomes extremely expensive in real-world apps, because of the typically large objects and the number of times they need to be compared.

So one work around is to have a policy to ask developers to create a new object whenever there is a change, then send it to the framework. And if there are no changes, then send back the old object as it is. In other words, new objects represent new states.

Note that you must clone old states using slice — or a similar mechanism — to copy old values into a new object.

Now, with this policy in place, you can compare two objects’ memory location using !== without having to compare each property within each object. And if the two objects are not the same, then you know that the object has changed state (that is, some property somewhere in the JavaScript object has changed). That’s exactly the strategy Redux employs to make things work.

So that’s why Redux needs for “Reducers” to be pure functions!

Per Redux Official Doc on Shallow Equality Checking

Why does Redux’s use of shallow equality checking require immutability? Redux’s use of shallow equality checking requires immutability if any connected components are to be updated correctly. To see why, we need to understand the difference between shallow and deep equality checking in JavaScript.

How do shallow and deep equality checking differ? Shallow equality checking (or reference equality) simply checks that two different variables reference the same object; in contrast, deep equality checking (or value equality) must check every value of two objects’ properties.

A shallow equality check is therefore as simple (and as fast) as a === b, whereas a deep equality check involves a recursive traversal through the properties of two objects, comparing the value of each property at each step.

It’s for this improvement in performance that Redux uses shallow equality checking.

However now a natural question is – Doesn’t Redux mitigate deep comparisons with essentially deep cloning? Isn’t it just moving the expensive operations to a different point in the lifecycle ?

And the ans

https://redux.js.org/faq/immutable-data#how-does-redux-use-shallow-equality-checking

“Redux uses shallow equality checking in its combineReducers function to return either a new mutated copy of the root state object, or, if no mutations have been made, the current root state object. combineReducers() function, iterates through each of these key/value pairs. At each stage of the iteration, combineReducers performs a shallow equality check on the current state slice and the state slice returned from the reducer.”

To update state immutability all the way down, a shallow copy at the level you’re modifying and all its parent levels is all you need.

let state = {
  a: {
    a1: "a1 initial value",
    a2: "a2 initial value"
  },
  b: {
    b1: "b1 initial value",
    b2: "b2 initial value"
  }
};

Now, if you just want to update a1? To do that, you need a copy of a and of state (because if you don’t copy state itself, you’re modifying the state tree it refers to, violating the immutability principal):

state = { ...state, a: { ...obj.a, a1: "updated a1" } };

Since one of the core tenets of Redux is to never mutate state, you’ll often find yourself using Object.assign() to create copies of objects with new or updated values. For example, in the todoApp below Object.assign() is used to return a new state object with an updated visibilityFilter property:

function todoApp(state = initialState, action) {
  switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return Object.assign({}, state, {
        visibilityFilter: action.filter
      });
    default:
      return state;
  }
}

While effective, using Object.assign() can quickly make simple reducers difficult to read given its rather verbose syntax.

An alternative approach is to use the object spread syntax recently added to the JavaScript specification. It lets you use the spread (…) operator to copy enumerable properties from one object to another in a more succinct way. The object spread operator is conceptually similar to the ES6 array spread operator. We can simplify the todoApp example above by using the object spread syntax:

function todoApp(state = initialState, action) {
  switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return { ...state, visibilityFilter: action.filter };
    default:
      return state;
  }
}

The advantage of using the object spread syntax becomes more apparent when you’re composing complex objects. Below getAddedIds maps an array of id values to an array of objects with values returned from getProduct and getQuantity.

return getAddedIds(state.cart).map(id =>
  Object.assign({}, getProduct(state.products, id), {
    quantity: getQuantity(state.cart, id)
  })
);

// Object spread lets us simplify the above map call to:

return getAddedIds(state.cart).map(id => ({
  ...getProduct(state.products, id),
  quantity: getQuantity(state.cart, id)
}));

In Redux all the application’s state lives in one immutable state-tree called store.

That store is at the fundamental level is a simple javascript object. And the reason its called immutable is because one does not simply modify the state tree. What we do is, we distribute action. State is read-only: The state cannot be changed directly by the view or any other process (maybe as a result of network callback or some other event). In order to change the state, you must express your intent by emitting an action. An action is a plain object describing your intent, and it contains a type property and some other data. Actions can be logged and later replayed which makes it good for debugging and testing purpose.

Why Immutable function and Immutable, persistent data-structure is so important in React

One approach to controlling changes is to favor immutable, persistent data structures. They seem to be a particularly good fit with React’s virtual DOM approach.

The thing about immutable data structures is that, as the name implies, you can never mutate one, but only produce new versions of it. If you want to change an object’s attribute, you’ll need to make a new object with the new attribute, since you can’t change the existing one. Because of the way persistent data structures work, this is actually much more efficient than it sounds.

What this means in terms of change detection is that when a React component’s state consists of immutable data only, there’s an escape hatch: When you’re re-rendering a component, and the component’s state still points to the same data structure (Meaning nothing was changed, i.e. no new Object was created or Cloned because there was no change) as the last time you rendered it, you can skip re-rendering. You can just use the previous virtual DOM for that component and the whole component tree stemming from it. There’s no need to dig in further, since nothing could possibly have changed in the state.

Pass by reference vs pass by value in pure JavaScript

To understand immutable data you need to understand that in JavaScript non-primitive types (objects, arrays, functions…) are passed by reference and primitive types (string, number, boolean, symbol, null and undefined) are passed by value. This means that primitive types are immutable by default and you can’t change them. Instead, when you pass a primitive type to another variable, it will get a new copy of that value. On the other hand non-primitive or compound data types, which are mutable.

Lets see an example

var a = {}; var b = {};

a === b // false

When you create new objects, arrays, functions, etc., a brand new object is placed into memory. Creating a new object with the same internals as another object will not magically cause that object to point to one that already exists. The objects may look the same, but they do not point to the same instance.

Non-Primitive data-types like Objects are not compared by value. This means that even if two objects have the same properties and values, they are not strictly equal. Same goes for arrays. Even if they have the same elements that are in the same order, they are not strictly equal.

Non primitive values can also be referred to as reference types because they are being compared by reference instead of value. Two objects are only strictly equal if they refer to the same underlying object.

// Primitive types are immutable by default
let x = 25;
let y = x;
y = 100;
console.log(x); // 25
console.log(y); // 100

// On the other hand, when you pass a variable of non-primitive type as an object to another variable, they will both point/refer to the same object.

// Non-primitive types are mutable
let animal = {
  name: "Mouse"
};

let anotherAnimal = animal;
anotherAnimal.name = "Elephant";
console.log(animal); // {name: "Elephant"}
console.log(anotherAnimal); // {name: "Elephant"}
console.log(animal === anotherAnimal); // true

So, how should you handle immutable data in JavaScript?

MOST IMPORTANT POINT – When you want to update an object you should create a completely new object, thus keeping it immutable. For that purpose you can use the Object.assign method or object spread syntax:

const animal = { name: "Mouse" };
// Object.assign
const anotherAnimal = Object.assign({}, animal, {
  name: "Elephant"
});
// This method Object.assign() - has a flaw that it only does a shallow copy. It means that nested properties are still going to be copied by reference. Be careful about it.

// Object spread operator
const yetAnotherAnimal = {
  ...animal,
  name: "Crocodile"
};
console.log(animal); // {name: "Mouse"}
console.log(anotherAnimal); // {name: "Elephant"}
console.log(yetAnotherAnimal); // {name: "Crocodile"}
console.log(animal === anotherAnimal); // false
console.log(animal === yetAnotherAnimal); // false

When dealing with arrays you should not use methods that will mutate the given array such as push, shift, unshift, reverse,sort and other array methods. Instead, you should use their immutable equivalents. As you might have already noticed, in the beginning of every chapter I was using the spread operator instead of thepush method to add a new string into our devSkills array.

const animals = ["Mouse", "Elephant"];
const animalsUpgrade = [...animals, "Crocodile"];
console.log(animals); // ["Mouse", "Elephant"]
console.log(animalsUpgrade); // ["Mouse", "Elephant", "Crocodile"]
console.log(animals === animalsUpgrade); // false

By virtue of using immutability approach your state will become more predictable, your application more performant and your code more testable and debuggable

A great Explanation from Dan on ‘Why cant state be mutated’

While cloning the states after a state change – and remember state being an object so the principle (stated above) generally holds true that – When you want to update an object you should create a completely new object – So this is what Dan had to say,

Some can say this technique of creating a new state object on every change to the store would tax the gc and performance in a large application. But not much performance effect was seen. Dan has further clarified below on this topic –

“state is not deeply cloned on every action. Only the parts that changed are cloned (again, not deeply, depends on what changed). For example, when a todo is edited in TodoMVC app, only that todo object is cloned. The rest of the todo objects are the same. Of course, a root new todo list array is created, pointing to the new object, but the objects themselves are not cloned if they have not changed. Therefore it’s not as expensive as it may seem. Furthermore, when it gets expensive (e.g. fast array changes), you can start using a library like Immutable.js that has very fast copying thanks to structural sharing. With Immutable.js, copying even large arrays isn’t really that expensive because large chunks of the memory are reused. Finally, whether with or without Immutable.js, immutability helps us efficiently rerender the app because we know what exactly has changed thanks to the objects not being mutated.”

Why reducers need to be pure functions

Redux takes a given state (object) and passes it to each reducer in a loop. And it expects a brand new object from the reducer if there are any changes. And it also expects to get the old object back if there are no changes.

Redux simply checks whether the old object is the same as the new object by comparing the memory locations of the two objects. Meaning if the memory-locations are different – its a change of State for Redux and re-rendering cycle is necessary, if memory-locations are same no change has occurred for Redux, so no re-rendering is required

So if you mutate the old object’s property inside a reducer, the “new state” and the “old state” will both point to the same object.

Because, in JavaScript non-primitive types (objects, arrays, functions…) are passed by reference. Hence Redux thinks nothing has changed! So this won’t work.

Further Reading

To Get Daily Health Newsletter

We don’t spam! Read our privacy policy for more info.

Download Mobile Apps
Follow us on Social Media
© 2012 - 2025; All rights reserved by authors. Powered by Mediarx International LTD, a subsidiary company of Rx Foundation.
RxHarun
Logo