【问题标题】:React state array object changes without setState在没有 setState 的情况下反应状态数组对象的变化
【发布时间】:2019-01-22 17:13:39
【问题描述】:

我有一个数组,它是 React 组件的状态。这个数组是一个清单。 var units1 = this.state.units;

当我更新 units1 时,this.state.units 会在没有 this.setState({ units: units1 }) 的情况下发生变化

我使用this.setState({ a: 2 }); 只是为了查看数组是否在没有this.setState({ units: units2 }); 的情况下更新

this.state.units 从 props 获取它的值,所以如果 state 改变,props 也会改变。

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 })
}

有人知道为什么会这样吗?

【问题讨论】:

  • 那是因为数组是引用类型,而不是值类型。当您更改 units1 时,您也在更改状态。先做一个数组的深拷贝。
  • 如何制作数组的深拷贝?这不是副本 var units1 = this.state.units.slice() 吗?
  • 假设你使用的是 ES6,你可以简单地使用 ... 操作符。而不是使用 var units1 = this.state.units.slice();使用 var units = [...this.state.units],操作并完成后,使用 setState 更新状态。
  • 这将起作用 var units1 = this.state.units.map(item=>item) for the units1 变量将是一个不可变对象
  • 使用 lodash.cloneDeep

标签: reactjs


【解决方案1】:

正如@Alexander van Oostenrijk 所说,要制作数组的深层副本。


因为数组是通过引用传递的,这意味着传递数组的内存地址而不是数组的值。
  var units1 = this.state.units.slice();

现在,units1 具有该数组的引用地址,对 units1 或 this.state.units.slice() 所做的任何更改都会更改两者的值。因为基本上它们正在使用地址,如果一个更改地址处的值,那么两者都会读取更改的值。希望您理解


要创建深层副本,您可以创建新对象,例如
var units1 = Object.assign([],this.state.units)

这将使用 this.state.units 的数据创建新对象 extras 我认为您不需要 .slice()。

【讨论】:

  • 我确实需要 slice() 以便我可以操作数组。我这样做了 var units1 = Object.assign({},this.state.units),但是当我尝试执行 units.slice() 时,我收到一个错误,即 slice() 不是函数
  • Object.assign([],this.state.units) 非常适合你。我正在更新我的 ans 再次查看。
猜你喜欢
  • 2019-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-25
  • 1970-01-01
  • 2018-02-14
  • 2019-06-13
相关资源
最近更新 更多