I have a state called this.state.devices
which is an array of device
objects.
Say I have a function
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});
}
}
Problem here is that every time this.updateSomething
is called, the entire array is updated, and so the entire DOM gets re-rendered. In my situation, this causes the browser to freeze as I am calling this function pretty every second, and there are many device
objects. However, on every call, only one or two of these devices are actually updated.
What are my options?
EDIT
In my exact situation, a device
is an object that is defined as follows:
function Device(device) {
this.id = device.id;
// And other properties included
}
So each item in the array of state.devices
is a specific instant of this Device
, i.e. somewhere I'd have:
addDevice: function (device) {
var newDevice = new Device(device);
this.setState({devices: this.state.devices.push(device)});
}
My updated answer how on to updateSomething
, I have:
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);
}
}
Problem now is that I get an error that says cannot read the undefined value of id
, and it is coming from the function Device()
; it seems that a new new Device()
is being called and the device
is not passed to it.
State can hold any kind of JavaScript value, including objects. But you shouldn't change objects that you hold in the React state directly. Instead, when you want to update an object, you need to create a new one (or make a copy of an existing one), and then set the state to use that copy.
myArray. push(1); However, with React, we need to use the method returned from useState to update the array. We simply, use the update method (In our example it's setMyArray() ) to update the state with a new array that's created by combining the old array with the new element using JavaScript' Spread operator.
To update an object in a state array, call the map() method to iterate over the array and update the object that matches the condition. Copied! const updateObjectInArray = () => { setEmployees(current => current.
To update our state, we use this. setState() and pass in an object. This object will get merged with the current state. When the state has been updated, our component re-renders automatically.
You can use the react immutability helpers.
From the docs:
Simple push
var initialArray = [1, 2, 3];
var newArray = update(initialArray, {$push: [4]}); // => [1, 2, 3, 4]
initialArray is still [1, 2, 3].
So for your example you will want to do something like this:
if (index !== -1) {
var deviceWithMods = {}; // do your stuff here
this.setState(update(this.state.devices, {index: {$set: deviceWithMods }}));
}
Depending on how complex your device
model is you could just 'modify' the object properties in situ:
if (index !== -1) {
this.setState(update(this.state.devices[index], {name: {$set: 'a new device name' }}));
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With