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