1

This function works properly and the component rerenders

  handleRemove = (e) => {
//console.log(e);
const arrayCopy = this.state.scanlist.filter((row) => row.ref + row.lot !== e.ref + e.lot);
this.setState({ scanlist: arrayCopy });};

This function changes the state but the component does not rerender

  handleAdd = (e) => {
//console.log(e);
const index = this.state.scanlist.findIndex((row) => row.ref === e.ref && row.lot === e.lot);
let scancopy = this.state.scanlist;
scancopy[index].qty = scancopy[index].qty + 1;
console.log(scancopy);
this.setState({ scanlist: scancopy });};

Does anyone see the issue? Mutation?

AHCB
  • 73
  • 1
  • 8
  • Does this answer your question? [Whats the best way to update an object in an array in ReactJS?](https://stackoverflow.com/questions/28121272/whats-the-best-way-to-update-an-object-in-an-array-in-reactjs) – Emile Bergeron Mar 30 '21 at 05:56

2 Answers2

3

Using Array.prototype.filter to remove an element from an array is pretty standard, but in the second handler yes, you've a state object mutation.

handleAdd = (e) => {
  const index = this.state.scanlist.findIndex((row) => row.ref === e.ref && row.lot === e.lot);
  let scancopy = this.state.scanlist;
  scancopy[index].qty = scancopy[index].qty + 1; // <-- state object mutation
  this.setState({ scanlist: scancopy });
};

You should shallow copy the scanlist array and the element that is being updated. Array.prototype.map is a common method to shallow copy the state array, and spreading the object properties of the element that needs to be updated shallow copies it. Anytime you are updating any nested state objects you should shallow copy the parent object.

handleAdd = (e) => {
  this.setState(prevState => ({
    scanlist: prevState.scanlist.map(
      (row) => row.ref === e.ref && row.lot === e.lot ? {
        ...row,
        qty: row.qty + 1,
      } : row)
  }));
};
Drew Reese
  • 165,259
  • 14
  • 153
  • 181
0

In the first approach filter method returns new list, whereas in the second approach it is just referencing to state array.

Try shallow copy in second approach,

let scancopy = [...this.state.scanlist]

Or

Simple deep copy approach,

let scancopy = JSON.parse(JSON.stringify(this.state.scanlist));
Viraj Jadhav
  • 84
  • 1
  • 2
  • 6
  • 2
    This first method still mutates the array elements, they need to be copied as well. The second, using JSON to serialize/deserialize is very anti-pattern. – Drew Reese Mar 30 '21 at 05:55
  • This improved the stability but there was an still an issue with one of the nested components that use this data. – AHCB Mar 30 '21 at 05:55
  • Oh. Does shallow copy still mutates the array elements ? @DrewReese. I have edited the solution to deep copy as well, thanks. – Viraj Jadhav Mar 30 '21 at 05:58
  • @DrewReese Do you think my first function needs changing also or is that correct in JS/React? – AHCB Mar 30 '21 at 05:59
  • 2
    Shallow copy of the array just means you've a new array reference, but the array elements are still references to the objects of the copied array. – Drew Reese Mar 30 '21 at 05:59
  • True ! Thanks. Got confused over there. – Viraj Jadhav Mar 30 '21 at 06:01