I have created dynamic Room components which are created based on a room object dispatched by Redux.
{
rooms && rooms.map((room, index) => {
const { name, temperature, humidity, timestamp } = room
return (
<Col key={index} xs={12} md={6}>
<Room
index={index}
name={name}
temperature={temperature}
humidity={humidity}
/>
</Col>
)
})
}
The details of each room are mounted properly. I create a function to maintain 10 objects in an array. However, when the array is passed into Rechart, it seems that my components are updating on top of the same state.
class Room extends Component {
linechart = () => {
const { timestamp, temperature, humidity, name } = this.props
const { chartData } = this.state
if(chartData.length > 9) chartData.shift()
chartData.push({
name,
timestamp: moment(timestamp).format('mm:ss'),
temperature,
humidity})
}
}
As you can see, the component details are displayed properly. However, the values of chartData are being stored in the same state, despite being unique components.
I ran the function with an interval of 1 second, and the logs show that the state is being updated in 0.5 second intervals. That means both <Room/>
components are using the same <LineChart/>
component.
Does anyone know how to overcome this issue?
In order to update items in an array
, I'd recommend using the spread syntax. Spread syntax works by shallow copying the array, which keeps a reference to the original array, but allows you to overwrite any data types stored within it. This keeps the array immutable.
I'm not sure where you're getting your data from, but since you have a finite amount of rooms
, then the array should already be structured like so:
data: [
{
name: "Room1",
humidity: 11,
tempature: 30,
timestamp: "Sat May 25 2019 22:23:06 GMT-0700",
},
{
name: "Room2",
humidity: 11,
tempature: 25,
timestamp: "Sat May 25 2019 22:23:06 GMT-0700",
},
...etc
]
Then you can simply store this to state
and when needed map over the array and update its properties with incoming data. However, this assumes incoming data contains all the rooms
. If you just need to update a specific room
within the rooms
array, then you can compare an id
(or something that uniquely identifies it) to an incoming new data id
.
For example, a new update comes in, but it's only updating Room1
, then we could do something like so..
incoming data
data: [
{
name: "Room1",
humidity: 11,
tempature: 30,
timestamp: "Sat May 25 2019 22:23:06 GMT-0700",
}
];
current data stored in state
as "rooms"
this.setState(prevState => ({
...prevState, // spread out any previous state not related to "rooms"
rooms: prevState.rooms.map(room => { // map over "rooms" and pull out each "room" object
return room.name === data[0].name // if the "room.name" matches incoming data's "name", then...
? { ...data[0] } // spread and overwrite it with incoming data
: room; // else leave the "room" as is
})
}));
Using array prototypes
like pop
and shift
mutate the original array stored within state
and React doesn't handle mutations to its state
. You can, however, clone
the room
array with Array.from() or simply create a new array instance and mutate this new instance with some array prototype
functions, but you must then re-set this new instance array to state
to overwrite the old array -- React handles this without a problem. It's just not as clean as the spread syntax.
Working example includes both spread syntax
and Array.prototype
options with a setInterval
:
Working example of randomly updating one item within an array by an id
with a setInterval
: