Why immutable state with redux

2020-03-01 10:11发布

问题:

I'm learning redux and am struggling to understand why state has to be immutable. Could you provide me with an example, in code preferably, where breaking the immutable contract results in an not so obvious side effect.

回答1:

Redux was originally invented to demonstrate the idea of "time-travel debugging" - being able to step back and forth through the history of dispatched actions, and see what the UI looks like at each step. Another aspect is being able to live-edit the code, reload it, and see what the output looks like given the new reducer logic.

In order to be able to properly step back and forth between states, we need to make sure that reducer functions have no side effects. That means data updates need to be applied immutably. If a reducer function actually directly modifies its data, then stepping back and forth between states will cause the application to behave in an unexpected fashion, and the debugging effort will be wasted.

Also, the React-Redux library relies on shallow equality checks to see if the incoming data for a component has changed. If the data references are the same, then the wrapper components generated by connect assume that the data has not changed, and that the component does not need to re-render. Immutable data updates means that new object references are created, and thus connect will see that the data has changed and the UI needs to update.



回答2:

Two Ideas

There are two ideas about immutability that you need to understand:

  • Mutate the state only in the reducers
  • Using an immutable data structure

Mutate the state only in the reducers

Redux tries to ensure that you only mutate the state in the Reducers. This is important because it makes easier to think about your application data flow.

Let's say that a value is not displayed in the UI as you expected or that a value that should have changed still showing its original value.

In that case, you could just think about which reducer is causing the mutation and see what went wrong.

This makes thinking about Redux issues very simple and makes developers highly productive.

Sometimes you can mutate the state in a view or in an action by mistake. If you think about the life-cycle:

Action -> Reducer -> Views-> Action 

If the state changes in a view and then an action is triggered the state change could be override. This would make very hard to find out what is going on for developers. We solve this by mutating state only in the reducers.

Note: another nice thing is that reducers are pure functions and all the async stuff takes places in the actions/middleware. So all side effects take place in the actions/middleware layer. Actions are our connection with the external world (HTTP, Local Storage, etc.).

Using an immutable data structure

As I have already mentioned, sometimes you can mutate the state in a view or in an action by mistake. To reduce chances of this happening we can make state mutations explicit by using and immutable data structure.

Using immutable data structures also has performance benefits because we don't need to perform deep equality checks to check for mutations.

The most commonly used provider of immutable data structures is immutable.js.



回答3:

I think the key ideas would be

  • Easy to replay any given situation/test flow - you can replay with the same actions starting from the same initial state
  • Fast component re-rendering - because the reference is changed and not its values, it is much much faster to test the change

Of course, there are other aspects and I suggest this nice article which explains in more details.



标签: redux