1

I have the following:

constructor() {
    super();
    this.state = {
        lists: [], 
        items: {}  
    };
}

So this.state.items is an object.

Now I have:

handleAddItem(s) {
    var key = Object.keys(s)[0];
    var value = s[key];

    var allItems = {...this.state.items};
    allItems[key].push({name: value});

    console.log(allItems);
    console.log(this.state.items);
}

this.state.items is initially null just {} and s is an object with a key value pair of name: snoopy

var s={};
   s[this.props.idName] = this.refs.id.value;

Why in the console.log are both the same?

DCR
  • 14,737
  • 12
  • 52
  • 115
  • What is the value of `s`? What would you expect to be the result of `{...this.state.items}`? – str Dec 03 '17 at 17:57
  • s is an object, key/value pair – DCR Dec 03 '17 at 17:58
  • no, it works fine – DCR Dec 03 '17 at 17:59
  • @DCR Yes that is obvious from your code. But what *exactly* is its value? It influences `key`/`value` and thus `allItems`. How are we supposed to answer when we don't know what you pass to that function? – str Dec 03 '17 at 18:00
  • it's just: name: snoopy – DCR Dec 03 '17 at 18:01
  • We cannot possibly know why unless you provide the exact values of `state.items` and `s`. Please add them to your question. – M0nst3R Dec 03 '17 at 18:01
  • Convert your object to string by using tostring. Again convert it by json.parse. it will create a fully new object as a duplicate. – mukund patel Dec 03 '17 at 18:14

2 Answers2

1

Spread syntax does work on the object. However Spread syntax effectively goes one level deep while copying an array. Hence allItems[key] would still reference the same object causing it to be mutated when you mutate allItems[key].

According to the MDN docs:

Note: Spread syntax effectively goes one level deep while copying an array. Therefore, it may be unsuitable for copying multidimensional arrays as the following example shows (it's the same with Object.assign() and spread syntax).

var a = [[1], [2], [3]];
var b = [...a];
b.shift().shift(); // 1
// Now array a is affected as well: [[], [2], [3]]

In case you wish to clone nested state, you would do

var allItems = {
    ...this.state.items, 
    [key]: [...this.state.items[key]]
};

var items = {
   x: ['a']
};
var value="abc"
var key='x'
var allItems = {
    ...items, 
    [key]: [...items[key]]
};
console.log(allItems, 'before');

allItems[key].push({name: value});
console.log(allItems);
console.log(items);
Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400
  • then how do you copy an object? – DCR Dec 03 '17 at 18:06
  • You are copying an object, just not a nested one. For a nested object, you would repeat the steps of spread syntax, or better use ImmutableJS – Shubham Khatri Dec 03 '17 at 18:06
  • then why is console.log the same – DCR Dec 03 '17 at 18:07
  • @ShubhamKhatri The question is about [*Object* Rest/Spread](https://github.com/tc39/proposal-object-rest-spread), not on an array. – str Dec 03 '17 at 18:07
  • @str, you would push to an array and my answer just explain that nested objects/arrays are not cloned by spread syntax, it just does a one level deep clone – Shubham Khatri Dec 03 '17 at 18:08
  • your answer doesn't help, sorry but this is so confusing. How do you copy an object and not mutate the original – DCR Dec 03 '17 at 18:10
  • thanks, so in my example is it ok to do what I did or should I make a copy? – DCR Dec 03 '17 at 18:14
  • @DCR, if you are setting a state at later point of time, you would still do the same, since setState overrides the state mutation. You could check this answer on updating a nested state, https://stackoverflow.com/questions/43040721/how-to-set-a-nested-state-in-react/43041334#43041334 . I hope I could explain the answer to you – Shubham Khatri Dec 03 '17 at 18:17
0

Spread works on objects.

Check the docs at here for more info. The results are the same because what spread does is copy references, so if you change any value (arrays, objects) it reflects on the original.

By using spread you're basically making a shallow copy not a deep copy, so the inner values remain intact.

codejockie
  • 9,020
  • 4
  • 40
  • 46