I'm new to Redux - and I'm really trying to get the big picture of using functional programming to make unidirectional data more elegant.
The way I see it- each reducer is taking the old state, creating a new state without mutating the old state and then passing off the new state to the next reducer to do the same.
I get that not causing side effects helps us get the benefits of a unidirectional flow of data.
I just really don't get what is so important about not mutating the old state.
The only thing I can think of is maybe the "Time-Traveling" I've read about because, if you held on to every state, you could perform and "undo".
Question:
Are there other reasons why we don't want to mutate the old state at each step?
Working with immutable data structures can have a positive impact on performance, if done right. In the case of React, performance often is about avoiding unnecessary re-rendering of your app, if the data did not change.
To achieve that, you need to compare the next state of your app with the current state. If the states differ: re-render. Otherwise don't.
To compare states, you need to compare the objects in the state for equality. In plain old JavaScript objects, you would need to deep compare in order to see if any property inside the objects changed.
With immutable objects, you don't need that.
basically does the trick. Or if you are using a lib like Immutable.js
Immutable.is(obj1, obj2)
.In terms of react, you could use it for the
shouldComponentUpdate
method, like the popularPureRenderMixin
does.This function prevents re-rendering, when the state did not change.
I hope, that contributes to the reasoning behind immutable objects.
Redux checks if the old object is the same as the new object by comparing the memory locations of the two objects. 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 and Redux will infer that nothing has changed.
No reasons. The are no any fundamental reasons that shouldComponentUpdate "pure render" optimization can't work with mutable state containers. This library does it, for instance.
https://github.com/Volicon/NestedReact
With immutable data the reference to the data structure itself can be used as version token. Thus, comparing the references you're comparing the versions.
With mutable data you will need to introduce (and compare) separate version tokens, which is hard to do manually but can easily be achieved with smart "observable" objects.
I'm pretty new to Redux (and React.js) too, but this is what I understand from learning this stuff.
There are several reasons why immutable state is chosen over the mutable one. First of all, mutation tracking is pretty difficult. For example when you are using a variable in several pieces of code and the variable can be modified in each of this places, you need to handle each change and synchronize results of mutation. This aproach in many cases leads to bidirectional data flows. Pieces of data are flowing up and down across the functions, variables and so on. Code starts beeing polluted by
if-else
constructions that are oly responsible for handling state changes. When you add some asynchronous calls your state changes can be even harder to track. Of course we can subscribe to data events (for exampleObject.observe
), but it can lead to situation that some part of application that missed change stays out of sync with other part of your program.Immutable state helps you to implement unidirectional data flow that helps you to handle all changes. First of all data flows from top to bottom. That means all changes that were applied to the main model are pushed to the lower components. You can always be sure that the state is the same in all places of the application, because it can be changed only from one place in the code - reducers. There is also one thing worth of mentioning - you can reuse data in several components. State cannot be changed (a new one can be created), so it's pretty safe to use same piece of data in several places.
You can find more information about pros and cons of mutability (and about the reason why it was chosen as a main approach of Redux) here:
The key of the "no-mutations" mantra is that if you can not mutate the object, you are forced to create a new one (with the properties of the original object plus the new ones). To update the components when an action is dispatched, Redux checks if the object is different, not if the properties have changed, so: