51

Why should objects in Redux be immutable? I know that some frameworks such as Angular2 will use onPush and can take advantage of immutability to compare states of views for faster rendering, but I am wondering if there are other reasons as Redux is framework agnostic and yet it mentions within its own docs to use immutability (regardless of the framework).

Appreciate any feedback.

Andrea Casaccia
  • 4,802
  • 4
  • 29
  • 54
born2net
  • 24,129
  • 22
  • 65
  • 104
  • 2
    It makes things easier to reason about, and helps to prevent you from accidentally changing the state outside of the Redux way of doing it. – Matthew Herbst Jan 23 '16 at 02:32
  • 3
    tx for the answer... but its kind of vague.. I know that's what they always say.. change a name from A to B does not make it more complex or harder to reason about... – born2net Jan 23 '16 at 02:48
  • 4
    Let me put it this way: if I know that a data structure is Immutable, I know there are parts of the code that absolutely cannot change it. That makes testing that code and finding bugs much much simpler. – Matthew Herbst Jan 23 '16 at 02:49
  • ok tx... to me interfaces data structure would sound like a more solid contract but that's just me I guess... in any case, I will use immutability as a pattern for the benefit of faster onPush rendering in ng2... tx – born2net Jan 23 '16 at 03:17
  • Yeah. JavaScript doesn't have all the nice rules that you can force with Java. ES6 brings a lot of the structure, but at the end of the day it's still very easily to trivially change things you didn't mean to change. – Matthew Herbst Jan 23 '16 at 03:24
  • I think redux is only CR you can't delete something and you can't update something you always create new state and with that your app is series of states and you can use travel debugging. – stojevskimilan Nov 28 '17 at 16:40
  • javascript is single threaded, if you pass an object representing state to a function it's not like it's going to change mid execution, because env is single threaded, while your function's code is running no other code is running. Java has threads, where immutability would be useful. – Muhammad Umer Dec 05 '19 at 20:12

5 Answers5

47

Redux is a small library that represents state as (immutable) objects. And new states by passing the current state through pure functions to create an entirely new object/application states.

If your eyes-glazed over there don't worry. To sum up, Redux does not represent changes in your application's state by modifying objects ( as you would with object-oriented paradigms). Instead state changes are represented as the difference between the input object and the output object (var output = reducer(input)). If you mutate either input or output you invalidate the state.

To sum up another way, immutability is a requirement of Redux because Redux represents your application state as "frozen object snapshots". With these discrete snapshots, you can save your state, or reverse state, and generally have more "accounting" for all state changes.

State of your app is only changed by a category of pure functions called reducers. Reducers have 2 important properties:

  1. They never mutate, returning newly built objects: This allows reasoning about input + output without side-effects
  2. Their signature is always function name(state, action) {}, so it makes it easy to compose them:

Assume the state looks like this:

    var theState = {
      _2ndLevel: {
        count: 0
      }
    }

We want to increment the count, so we make these reducers

const INCR_2ND_LEVEL_COUNT = 'incr2NdLevelCount';

function _2ndlevel (state, action) {
    switch (action.type) {
        case INCR_2ND_LEVEL_COUNT:
            var newState = Objectd.assign({}, state);
            newState.count++
            return newState;
        }
    }

function topLevel (state, action) {
    switch (action.type) {
        case INCR_2ND_LEVEL_COUNT:
            return Object.assign(
                {}, 
                {_2ndLevel: _2ndlevel(state._2ndlevel, action)}
            );
    }
}

Note the use of Object.assign({}, ...) to create an entirely new objects in each reducer:

Assuming we have wired up Redux to these reducers, then if we use Redux's event system to trigger a state change ...

    dispatch({type: INCR_2ND_LEVEL_COUNT})

...Redux will call:

    theNewState = topLevel(theState, action);

NOTE: action is from dispatch()

Now theNewState is an entirely new object.

Note: You can enforce immutability with a library (or new language features), or just be careful to not mutate anything :D

For a deeper look, I highly recommend you checkout this video by Dan Abramov (the creator). It should answer any lingering questions you have.

Ashley Coolman
  • 11,095
  • 5
  • 59
  • 81
  • 7
    first let me say thank you for the answer, I +1 you. But with that, let me explain, I am very aware of how Redux works, I already use it, my question is of deeper thought. Think about it, if you changed a name instead of replacing the entire object that held the name, you can STILL achieve "frozen object snapshots". The only reason (and that may be a good enough reason) is for speed comparison. Since it may be faster to compare new objects vs changed ones when freezing states. That would be the only reason I could see... tx Sean. – born2net Jan 23 '16 at 15:04
  • 2
    Ahhh ok - whoops :P. Hmm, I don't understand how a "frozen object snapshots" is achieved when you change a name, as you have then changed the object. But regardless, I think you are on the right track. The focus on immutability is because the _computation economics_ that occur in a typical SPA, lend themselves to shallow/dumb object comparison recreating state. Imagine it was not a name that you modified, but a name in a single cell of a 1000 rows in a rendered table. Re-rendering the table when _something_ changes is faster than traversing the entire state to find out _exactly what_ changed. – Ashley Coolman Jan 23 '16 at 17:50
  • 9
    I don't see how this answers the question "Why state should be immutable". Yes it explains a lot how to do it and just repeats Redux specification: "state should be immutable", but no description/explanation of the motivation behind it. If there would be any reason for application states to describe transitions (changes) one would just make **Objectd.assign({}, ...)** before and after any pure function calls. – Slaus Mar 11 '17 at 10:24
  • 1
    @AshleyCoolman - so continuing your array example from above - If I was to change the cell value and return the same array - would the component not be re-drawn or would it just take longer for the library to tell what changed? In the latter case the requirement for immutability is more of a performance recommendation. – Erez Cohen May 09 '17 at 14:37
  • 2
    @ErezCohen if you mutate the insides of an object, the object is still the same - thus the cheap comparison that redux makes won't notice the change. You need to return a new top level object. https://facebook.github.io/immutable-js/ is one way to enforce this. – Ashley Coolman May 11 '17 at 07:25
  • Objectd.assign() is not deep copy. So in your example, after var newState = Objectd.assign({}, state); then newState.count++, the original state changed. – Xig480 Nov 29 '19 at 17:04
  • This answer doesn't give a root of the reason. It just says that redux uses an immutable state, but doesn't explain the reason. – WebBrother Jan 21 '22 at 09:56
16

The following benefits of immutability are mentioned in Redux documentation:

  • Both Redux and React-Redux employ shallow equality checking. In particular:
    • Redux's combineReducers utility shallowly checks for reference changes caused by the reducers that it calls.
    • React-Redux's connect method generates components that shallowly check reference changes to the root state, and the return values from the mapStateToProps function to see if the wrapped components actually need to re-render. Such shallow checking requires immutability to function correctly.
  • Immutable data management ultimately makes data handling safer.
  • Time-travel debugging requires that reducers be pure functions with no side effects, so that you can correctly jump between different states.
Andrea Casaccia
  • 4,802
  • 4
  • 29
  • 54
  • In other words, ignoring the recommendation and mutating `state` will mess with the "should component update" logic? Is it possible to say in what way this will go wrong, i.e., will rendering happen always / never / it depends? – bluenote10 Jun 30 '17 at 06:04
  • 1
    The answer to your question is not trivial. It depends on how your state is structured, what deep property you are changing and if you are using `combineReducers` and/or `react-redux`. You can definitely know what's going to happen with a deeper understanding of `combineReducers` and `react-redux`. In general, when a deep change is not detected because of a shallow check, some components in your UI are not going to update. But the bottom line is _don't mutate the state_. It is a Bad Thing™. – Andrea Casaccia Jun 30 '17 at 06:57
  • For the first time they copied all object, than they said that "shallow" comparison with it is fast. xD lol. I started to hiccup. – puchu Jul 17 '18 at 11:00
  • @bluenote10 you are free to mutate some part of your state, don't listen to functional fanatics. Immutability is a sacred relic that has nothing to do with JS. Please read more about `react` + `mobx` or `vue.js`. – puchu Jul 17 '18 at 11:14
8

The main reason Redux is using immutability is that it doesn't have to traverse an object tree to check for the changes in every key value. Instead, it will only check the object's reference is changed or not in order to update DOM on state change.

  • This is incorrect as the UI layer still has to traverse the entire Object tree (i.e. the new state) to see what has changed – user1034912 Jan 09 '22 at 23:35
1

Greate article https://medium.cobeisfresh.com/how-redux-can-make-you-a-better-developer-30a094d5e3ec

Along with immutable data, pure functions are one of the core concepts of functional programming

zloctb
  • 10,592
  • 8
  • 70
  • 89
  • If function is processing only immutable data it is pure. But it is not reversible. There are pure functions that mutates data. It is possible to create pure function from impure function groups. This concept is ancient and it is not full. Do not poison people brain. – puchu Jul 17 '18 at 11:28
0

Based on the official docs :

There are several reasons why you must not mutate state in Redux:

  • It causes bugs, such as the UI not updating properly to show the latest values
  • It makes it harder to understand why and how the state has been updated
  • It makes it harder to write tests
  • It breaks the ability to use "time-travel debugging" correctly
  • It goes against the intended spirit and usage patterns for Redux

Reudx official docs

alithecodeguy
  • 125
  • 1
  • 5