1

Unlike this post, I don't want to add a new item in the array, but I want to modify the item at the index i for instance.

Is there a solution other than deep-cloning the entire array like that?

const oldList = this.state.list;
let newList = JSON.parse(JSON.stringify(oldList));
newList[i] = "foo";
this.setState({list: newList});

Thank you for your help.

JacopoStanchi
  • 1,962
  • 5
  • 33
  • 61
  • Depends on whether item is object or primitve – charlietfl Feb 11 '19 at 00:40
  • You mean the spread operator will only work if the items are primitive types? – JacopoStanchi Feb 11 '19 at 00:42
  • No but shallow copying an array of objects will create multiple arrays of same object references at each index. Also depends on what your expectations are – charlietfl Feb 11 '19 at 00:46
  • But shallow copying an array of primitives is also deep cloning, and I wondered if there was no alternative to that. Besides, I don't know if it creates problems in React if you directly modify the object referenced in a state array, like that for example: `this.state.list[3].text = "foo";`. In itself, the object referenced by `this.state.list[3]` is not in the state. – JacopoStanchi Feb 11 '19 at 00:51
  • Alternatives are `Array#slice()` or spread which are less overhead than JSON methods – charlietfl Feb 11 '19 at 00:54

1 Answers1

2

You can use spread.

const oldList = this.state.list;
let newList = [...oldList];
newList[i] = "foo";
this.setState({ .list: newList });

But the spread will not work if the elements of array are object. Since it will only make a new copy of array that reference to the old object. But in your case, you assign string. So it is primitve type.


So if I'm correct, the spread operator will basically do a deep-cloning

Spread does shallow cloning. Think array spread same as creating new array and copy all old value to the new array

a = [...b];

is the same as

a = [];
for(let i = 0; i < b.length; i++) a.push(b[i]);

because Vue overrides mutation methods on arrays like push(...)

For push, you can also use spread

a = [...b, 'new item'];

And for pop, you can use splice

a = b.slice(-1, 1);
invisal
  • 11,075
  • 4
  • 33
  • 54
  • So if I'm correct, the spread operator will basically do a deep-cloning. If the items are of type object, we must use `JSON.parse(JSON.stringify(oldList))`, am I wrong? That's one shortcoming of React compared to Vue.js, because Vue overrides mutation methods on arrays like `push(...)` or `pop(...)` so that you can use them no problem. – JacopoStanchi Feb 11 '19 at 00:45
  • Thank you for your edit. So there's no way to modify the item at index `i` in one line using just one `this.setState(...)`? We must before copy the array and update the item? – JacopoStanchi Feb 11 '19 at 01:07