Redux: why use Object.assign if it doesn't execute a deep clone?

One core concept in Redux is immutable states. However, I have seen many examples, including in Redux docs , using javascript Object.assign . Then I saw this warning in MDN :

For deep cloning, we need to use other alternatives, because Object.assign () copies property values. If the original value is a reference to an object, it copies only that reference value.

So why use Object.assign if the whole meaning is unchanged? Am I missing something?

+7
javascript redux
source share
3 answers

Take a look at the example you provided:

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

Yes, this is a shallow copy of state , creating a new object with everything from the old, but with an updated visibilityFilter . But if you agree on an incurable consideration of objects, then it is fine if the new state and the general state of sharing refer to other immutable objects. Later, presumably, if you had changed something, you would have followed the same pattern. At this point, the shallow copy that we made above will continue to use the old one, and your new object will use the new one.

If you apply immutability to the end, a shallow copy at the level you are changing and all of its parent levels is all you need. In the above example, the modification is at the top level, so this is only one copy.

But what if it were deeper? Let's say you had this object:

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

If you want to update a , this is exactly the same as the state example above; you would do this with just one small copy of obj :

 obj = Object.assign({}, obj, {a: {a1: "new a1", a2: "new a2"}}); 

or distribution properties (currently in step 3, usually included in the JSX transporter settings, ES2018 may be created):

 obj = {...obj, a: {a1: "new a1", a2: "new a2"}}; 

But what if you just want to upgrade a1 ? To do this, you need a copy of a and of obj (because if you do not copy obj , you change the tree to which it refers, violating the principal)

 obj = Object.assign({}, obj, {a: Object.assign({}, obj.a, {a1: "updated a1"})}); 

or with distribution properties:

 obj = {...obj, a: {...obj.a, a1: "updated a1"}}; 
+7
source share

Redux is just a data warehouse. Thus, in the purest sense, redux really needs neither immutability nor deep cloning to work as a concept.

However, redux requires immutability to work well with user interface infrastructures that are built on top of it (like React).

For this simple reason: What parts of my state changed the last time the structure looked?

Given this goal, can you see how deep cloning really doesn't help? If you look at one object that has been deeply cloned, then each sub-part of this object is now different from its identity ( === ).

As a concrete example, if you run the following code:

 const bookstore = { name: "Jane books", numBooks: 42 }; const reduxData = { bookstore, employees: ['Ada', 'Bear'] }; 

Now let's say you want to change only the number of books you have in the bookstore.

If you made a deep copy, for example:

 const reduxClone = JSON.parse(JSON.stringify(reduxData)); reduxClone.bookstore.numBooks = 25; 

Then you will see that both the bookstore and the employees are now different:

 console.log(reduxData.bookstore === reduxClone.bookstore); // returns false console.log(reduxData.employees === reduxClone.employees); // returns false, but we haven't changed the employees 

This is a problem because it looks like everything has changed. And now React has to redisplay everything to see if something has changed.

The correct solution is to use a simple rule of immutability. If you change the value of an object, you need to create a new copy of this object. So, since we need new numBooks, we need to create a new bookstore. And since we have a new bookstore, we need to create a new redux store.

 const newBookstore = Object.assign({}, bookstore, {numBooks: 25}); const shallowReduxClone = Object.assign({}, reduxData, {bookstore: newBookstore}); 

Now you will see that the bookstores have changed (yay!), But the employees do not (double yay!)

 console.log(reduxData.bookstore === shallowReduxClone.bookstore); // returns false console.log(reduxData.employees === shallowReduxClone.employees); // returns true 

Hope this example helps. Invariance allows you to change the smallest number of objects when making changes. If you guarantee that you will never modify an object, you can reuse this object in other trees that you create. In this example, we could use the employees object twice, without danger, because we promised never to mutate the employees object.

+1
source share

Inevitability means: I (as a developer) never assign the properties of an object to new values; either because the compiler doesn’t allow this, the object is frozen, or I just don’t do it. Instead, I create new objects.

If you always remember that you should not mutate objects and obey them, you will never change the contents of an existing object, even if you copied it small in advance, instead of deep copying (modifying existing objects is something that avoids errors, because this makes code behavior more predictable).

Thus, to create a solid code, you do not need deep copying.

Why avoid deep copying?

  • better shallow copy performance
  • less shallow copy memory

An example of including code without the need for a deep copy ( Object.assign used behind the scenes):

 const state = { firstName: 'please tell me', lastName: 'please tell me' } const modifiedState = { ...state, firstName: 'Bob' } 

Of course, you can do it wrong if you make a shallow copy instead of a deep copy of the object:

 const state = { firstName: 'please tell me', lastName: 'please tell me' } const modifiedState = state modifiedState.firstName = 'Bob' // violates immuting, because it changes the original state as well 
0
source share

All Articles