ReactJS, обновляющий один объект внутри массива состояний

У меня есть состояние с именем 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. Однако при каждом вызове фактически обновляется только одно или два из этих устройств.

Каковы мои варианты?

ИЗМЕНИТЬ

В моей точной ситуации a 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);
    }
}

Проблема в том, что я получаю сообщение об ошибке, которое не может читать значение undefined id, и оно исходит от function Device(); кажется, что новый new Device() вызывается, а device не передается ему.

Ответ 1

Вы можете использовать помощники по неизменности.

Из документов:

Простой push

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, вы можете просто "изменить" свойства объекта in situ:

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

Ответ 2

На мой взгляд, с реакционным состоянием, сохраняйте вещи, которые действительно связаны с "состоянием", например, вещи включаются, выключаются, но, конечно, есть исключения.

Если бы я был вами, я бы вытащил массив устройств в качестве переменной и установил там вещи, поэтому я могу что-то сделать:

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

И я импортировал update из immutability-helper на основе примечания: https://reactjs.org/docs/update.html