1

When using Redux, I have my initial state:

const initialState = {
  foo: {
    bar: {
      foobar: 1,
      barfoo: 2
    }
  },
  xyz: true,
  abc: {
    jkl: [1,2,3,4]
  }
}

Then I have the reducer, and inside a switch. Suppose I have a case X in which I want to change xyz to false.

Is this enough?

return {
  ...state,
  xyz: false 
}

or should I do?

return {
  foo: {
    bar: {
      ...state.foo.bar
    }
  },
  xyz: false,
  abc: {
    jkl: [...state.abc.jkl]
  }
}
nick
  • 2,819
  • 5
  • 33
  • 69

3 Answers3

1

No need to do your second implementation! That would create a catastrophe of reducers lol.

Just use:

return {
  ...state,
  xyz: false 
}

Not only is this the way that is advised in Redux apps, imagine having to debug reducers where you use your second implementation, and you make typos.

On the case of nested properties, you would need to do something like this:

return {
   ...state, 
   foo: { 
      bar: { ...state.foo.bar, roflWaffle: 3 } 
   } 
}

Also, recommend checking out other answers here too, very helpful in depth information that will greatly help you understand how JavaScript and Redux works under the hood.

Dan Zuzevich
  • 3,651
  • 3
  • 26
  • 39
1

It is enough if you are aware that the spread operator only does a shallow clone:

const a = {x: {y: 10}};
const b = {...a};

b.x.y = 42;

console.log(b.x.y); //=> 42
console.log(a.x.y); //=> 42

I understand that with Redux you want to return new state. Just know that this potentially opens up the gate to unwanted mutations and side effects.

With this simple example, I have shown how a simple reducer can potentially tamper with the history of your Redux states.

customcommander
  • 17,580
  • 5
  • 58
  • 84
  • As long as you follow the rule of reducers, and don't directly mutate the objects, he should be fine. However, I think this is a very important point for newcomers to realize that they should be reassigning like you do in your example. – Dan Zuzevich Jun 07 '20 at 21:12
  • It also brought up a good point that, if you are dealing with nested objects, you need to account for that, which @slezica very astutely pointed out – Dan Zuzevich Jun 07 '20 at 21:14
  • @DanZuzevich Isn't it what I also pointed out? (Not taking any credits away from slezica of course) – customcommander Jun 07 '20 at 21:16
  • Yeah, you are correct. Boo me for speed reading. My apologies. Gave an up vote. – Dan Zuzevich Jun 07 '20 at 21:19
0

Dan's answer gives you a practical and working syntax (do that! it's cleaner), but let's understand why.

Each spread copy is shallow, not deep. Only the first level is duplicated. For example, let's say you attempt to clone an object this way:

> let original = { someNumber: 1, someArray: [1, 2] }
> let copy = { ...original }

The objects original and copy are distinct. If you set properties, they won't reflect each other.

> x2.someNumber = 2
> x2.newProperty = "hello"

> console.log(x1)
{ someNumber: 1, someArray: [1,2] } // same someNumber, no newProperty!

But the value of each individual key is not duplicated, it's just a reference to the original. The someArray property references the very same array instance in both objects. So:

> console.log(x1.someArray)
[1, 2]

> x2.someArray.push(3)
> console.log(x1.someArray)
[1, 2, 3]

Both original.someArray and copy.someArray are referencing the same array instance. Two references in two objects, but only one underlying array.

There's no easy, 100% foolproof way to actually clone an object, because not all objects are simple JSON-like dictionaries. But you have some options in this other answer.

When working with React and Redux, many problems can be avoided by using a library like ImmutableJS, which ensures each object is distinct and every modification produces a different object. The performance is good and the syntax more comfortable in many cases, as well.

salezica
  • 74,081
  • 25
  • 105
  • 166
  • 1
    I like the in-depth coverage, very helpful for beginners, which I assume Nick is. – Dan Zuzevich Jun 07 '20 at 21:15
  • What are x1 and x2 objects? It might be easier to use examples to original and copy objects. – Dan Zuzevich Jun 07 '20 at 21:24
  • `But the value of each individual key is not duplicated, it's just a reference to the original.` I think you may confuse people. I know you meant this for `someArray` only but people may think this applies to all keys. – customcommander Jun 07 '20 at 21:33
  • Hi, thanks for this answer, I get it. But, if only using reducers and not changing the values directly, it shouldn't be a problem, right? – nick Jun 08 '20 at 03:27