1

If my state looks like this:

const initialState = {
  color: 'blue',
  sizes: ['S', 'M', 'L'],
}

And I want to change the color, my reducer should return this right:

return { ...state, color: newColor };

But won't the state still reference the old array? Is this considered a mutation even though I'm not modifying the array? Would this be better?

return {
  ...state,
  color: newColor,
  sizes: state.map.sizes(size => size)
}

And what if the array contains objects?

const initialState = {
  color: 'blue',
  sizes: [
    { color: 'red', size: 'S' },
    { color: 'green', size: 'M' },
    { color: 'blue', size: 'L' }
  ],
}

Does this mean I have to do this to avoid mutating the state?

return {
  ...state,
  color: newColor,
  sizes: state.map.sizes(item => { ...item })
}



Also, is there a reason Object.assign and the spread operator are preferred over doing JSON.stringify and JSON.parse?

1 Answers1

0

No, it's not a mutation. What you are doing is perfectly fine.

Have a look:

const obj1 = {
  a: 1,
  b: 2,
  c: 3
};

const obj2 = {
  ...obj1,
  c: 4
};

At no time is any member of the first object being changed, when the second object is being created.

In a Redux situation (or really, any time in an FP codebase, with pure functions) there is no harm in sharing references, as long as the references are read-only.

This means that when you are constructing a new object, its properties can happily be direct-references to the other object's properties, so long as you do not mutate any sub-properties (because those sub-properties would be shared objects).

Norguard
  • 26,167
  • 5
  • 41
  • 49
  • That's what I realized after a while. It doesn't matter if both the old and the new state reference the same array because I didn't modify it. I can still perform equality checks and go back to the previous state if necessary. –  Jan 31 '17 at 05:20
  • 1
    @epiqueras and that's why it's a great practice, if you grow the discipline to copy and not modify anything, it offers very quick and easy identity checks. There are, of course libraries of different flavours (ImmutableJS and various FP lens libraries) but if you're on your own or you have a passionate team, there's no reason you can't use vanilla JS objects this way. Especially with the future-specced Object rest/spread patterns. – Norguard Jan 31 '17 at 05:26
  • Yes, I can totally see this becoming a pain when dealing with complex array and nested property modifications. I just checked out some of those libraries and will definitely use them if I ever need to do more complex operations. I also try to compose reducers and keep the state as flat as possible to avoid it. –  Jan 31 '17 at 05:30
  • @epiqueras It's honestly not too bad at all, if your reducers are tiny and well built. Your objects can be nested as well, just be sure to rotate out any objects that might have made sense further down, but need to be shared by multiple parts of the state. – Norguard Jan 31 '17 at 05:32