ReactJS在状态数组中更新单个对象

ReactJS updating a single object inside a state array

本文关键字:更新 单个 对象 数组 状态 ReactJS      更新时间:2023-09-26

我有一个名为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没有传递给它。

你可以使用react的不变性帮助。

From the docs:

简单推

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

在我看来,react state只存储与"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});
           }
        }
    }
});

由于某些原因,以上答案对我不起作用。经过多次试验,下面的代码成功了:

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

我解决它做一个数组拼接的对象,我希望修改,之前更新组件状态和再次修改的对象推送。

就像下面的例子:

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