【问题标题】:ReactJS updating a single object inside a state arrayReactJS 更新状态数组中的单个对象
【发布时间】:2015-11-21 04:54:31
【问题描述】:

我有一个名为this.state.devices 的状态,它是device 对象的数组。

说我有一个函数

updateSomething: function (device) {
    var devices = this.state.devices;
    var index = devices.map(function(d){
        return d.id;
    }).indexOf(device.id);

    if (index !== -1) {
       // do some stuff with device
       devices[index] = device;
       this.setState({devices:devices});
    }
}

这里的问题是每次调用this.updateSomething 时,整个数组都会更新,因此整个DOM 会重新渲染。在我的情况下,这会导致浏览器冻结,因为我每秒都在调用这个函数,并且有很多 device 对象。但是,每次通话时,实际上只有一两个设备得到更新。

我有什么选择?

编辑

在我的确切情况下,device 是一个定义如下的对象:

function Device(device) {
    this.id = device.id;
    // And other properties included
}

所以state.devices 数组中的每个项目都是这个Device 的特定时刻,即我应该有的地方:

addDevice: function (device) {
    var newDevice = new Device(device);
    this.setState({devices: this.state.devices.push(device)});
}

我更新的答案如何updateSomething,我有:

updateSomething: function (device) {
    var devices = this.state.devices;
    var index = devices.map(function(d){
        return d.id;
    }).indexOf(device.id);

    if (index !== -1) {
       // do some stuff with device
       var updatedDevices = update(devices[index], {someField: {$set: device.someField}});
       this.setState(updatedDevices);
    }
}

现在的问题是我收到一个错误,说无法读取id 的未定义值,它来自function Device();似乎正在调用一个新的 new Device() 并且 device 没有传递给它。

【问题讨论】:

标签: javascript reactjs


【解决方案1】:

您可以使用反应immutability helpers

来自文档:

简单推送

var initialArray = [1, 2, 3];
var newArray = update(initialArray, {$push: [4]}); // => [1, 2, 3, 4]

initialArray 仍然是 [1, 2, 3]。

因此,对于您的示例,您需要执行以下操作:

if (index !== -1) {
    var deviceWithMods = {}; // do your stuff here
    this.setState(update(this.state.devices, {index: {$set: deviceWithMods }}));
}

根据您的device 模型的复杂程度,您可以就地“修改”对象属性:

if (index !== -1) {
    this.setState(update(this.state.devices[index], {name: {$set: 'a new device name' }}));
}

【讨论】:

  • 我的initialArray 是一个对象的瞬间数组;即我有MyObject()initialArray.push(new MyObject(object)) 是我添加它们的方式。当我尝试你的方法时,我在初始化期间在这个对象内部得到了一个错误。它说无法读取未知的属性;它正在object 中寻找一个字段。这是update 重新创建每个对象,这就是它失败的原因吗?
  • 我认为你正在改变状态的结构。在 var updatedDevices... 行之前检查 devices 并在之后检查 updatedDevices。我认为结构会有所不同。
  • 即使我注释掉 this.setState,我仍然会收到同样的错误。引发此错误的是 help 函数。
【解决方案2】:

在我看来,react state 只存储真正与“状态”相关的东西,比如开启、关闭,当然也有例外。

如果我是你,我会将设备数组作为变量提取并在那里设置,所以我可能会做:

var devices = [];

var MyComponent = React.createClass({
    ...
    updateSomething: function (device) {

        var index = devices.map(function(d){
            return d.id;
        }).indexOf(device.id);

        if (index !== -1) {
           // do some stuff with device
           devices[index] = device;

           if(NeedtoRender) {
               this.setState({devices:devices});
           }
        }
    }
});

【讨论】:

    【解决方案3】:

    由于某种原因,上述答案对我不起作用。经过多次试验,以下是:

    if (index !== -1) {
                let devices = this.state.devices
                let updatedDevice = {//some device}
                let updatedDevices = update(devices, {[index]: {$set: updatedDevice}})
                this.setState({devices: updatedDevices})
        }
    

    我根据来自https://reactjs.org/docs/update.html 的注释从immutability-helper 导入了update

    【讨论】:

      【解决方案4】:

      在更新组件状态并再次推送修改的对象之前,我解决了它在我希望修改的对象中进行数组拼接。

      如下例:

      let urls = this.state.urls;
      
      var index = null;
      
      for (let i=0; i < urls.length; i++){
        if (objectUrl._id == urls[i]._id){
          index = i;  
        }
      }
      
      if (index !== null){
        urls.splice(index, 1);  
      }
      
      urls.push(objectUrl);
      
      this.setState((state) => {
        return {urls: urls}
      }); 
      

      【讨论】:

        猜你喜欢
        • 2021-01-24
        • 1970-01-01
        • 1970-01-01
        • 2021-05-09
        • 2020-07-01
        • 2022-01-06
        • 1970-01-01
        • 2017-04-25
        • 1970-01-01
        相关资源
        最近更新 更多