1
votes

I have an array which is a state of the React component. This array is a checklist. var units1 = this.state.units;

when I update units1, this.state.units changes without the this.setState({ units: units1 })

I use this.setState({ a: 2 }); just to see if the array was updated without this.setState({ units: units2 });

this.state.units gets its value from props so if the state changes the props also changes.

handleItemChange(e) {
  var units1 = this.state.units.slice();        
  var unit_name = parseInt(e.target.attributes.getNamedItem('data-unit_name').value);
 var new_unit;

  if (!e.target.checked && this.state.units && this.state.units.length > 0) {
  this.state.units.map((unit) => {
    if (unit_name == unit.codpacunidad) {
      if (unit.topics && unit.topics.length > 0) {
        unit.topics.map((topic) => {
          if (topic.codpacunidadtema == e.target.name) {
            new_unit = unit;
            var index = units1.indexOf(unit);
            //units1.splice(index, 1);

            units1 = update(units1, {$splice: [[index, 1]]})

            var topics1 = unit.topics.slice();
            index = topics1.indexOf(topic);
            //topics1.splice(index, 1);

            topics1 = update(topics1, {$splice: [[index, 1]]})

            new_unit.topics = topics1;
          }
        });
      }
    }
  });
} else {
  var found_unit = false;
  var name = parseInt(e.target.name);
  var order = parseInt(e.target.attributes.getNamedItem('data-order').value);
  var unit_order = parseInt(e.target.attributes.getNamedItem('data-unit_order').value);

  if (this.state.units && this.state.units.length > 0) {
    this.state.units.map((unit) => {
      if (unit.codpacunidad == unit_name) {
        found_unit = true;
        new_unit = unit;
        var index = units1.indexOf(unit);
        units1.splice(index, 1);

        var new_topic = {
          codpacunidadtema: name,
          orden: order
        };

        var topics2 = new_unit.topics;
        new_unit.topics = update(topics2, { $push: [new_topic]});
      }
    });
  }

  if (found_unit == false) {
    new_unit = {
      codpacunidad: unit_name,
      orden: unit_order,
      topics: [{codpacunidadtema: name, orden: order }]
    };
  }
}

// var units2 = update(units1, { $push: [new_unit]});
// this.setState({ units: units2.sort(function(a, b) {
//     return parseInt(a.orden) - parseInt(b.orden);
//   })
// });

this.setState({ a: 2 }); //just to test if the array gets updated without this.setStaet({ units: units2 })
}

Anybody knows why this is happening?

1
That's because an array is a reference type, not a value type. When you change units1 you're also changing the state. Make a deep copy of the array first. - Alexander van Oostenrijk
how do i make a deep copy of the array? isn't this a copy var units1 = this.state.units.slice()? - Juan Felipe Gomez
assuming you are using ES6, you could just simply use the ... operator. instead of using var units1 = this.state.units.slice(); use var units = [...this.state.units], manipulate and once done, use the setState to update the state back. - Sreekanth
This woul work var units1 = this.state.units.map(item=>item) for the units1 variable will be an inmmutable object - Angel
Use lodash.cloneDeep - AmirHossein

1 Answers

0
votes

As @Alexander van Oostenrijk said to make deep copy of array.


  var units1 = this.state.units.slice();

Now units1 has the reference address of that array any change made to units1 or this.state.units.slice() will change value of both.As basically they are using address and if one change the value at address then both will read changed value.Hope you understand


var units1 = Object.assign([],this.state.units)

This will create new object with data of this.state.units extras I think you do not need .slice().