Reputation: 7105
I'm mapping an array inside a map function and I want to add the id of every element inside the array to a state. I'm facing an issue where just the last item is added to the array even though console log shows that the function iterates to correct number of times.
This is the code I have written
const { evc } = this.props;
evc.chargingStationGroups && evc.chargingStationGroups.map((item, key) => {
item.stations.map((stationItem, key) => {
console.log("stationID ",stationItem.stationID);
var stationId = {};
stationId = {
stationId: stationItem.stationID
}
var allIdArray = this.state.stationIdArray.concat(stationId);
this.setState({ stationIdArray: allIdArray })
})
})
Here evc.chargingStationGroups
is something like this
[
{
groupId: "16",
groupName: "Sia",
stations: [{stationId: "8", name: "Test"},{stationId: "9", name: "Test2"},{stationId: "10", name: "Test3"}]
},
{
groupId: "17",
groupName: "Maroon5",
stations: [{stationId: "10", name: "Test"},{stationId: "11", name: "Test2"},{stationId: "10", name: "Test3"}]
}
],
How can i add all stationItem.stationID
to my array, not just the last one.
Upvotes: 2
Views: 846
Reputation: 4068
Original answer: What happens when using this.setState multiple times in React component?
In brief, this.setState
is batched and called only once at the end of the loop, leaving this.state.stationIdArray
empty all the time. Hence only the result at the final iteration of this statement is kept:
var allIdArray = this.state.stationIdArray.concat(stationId);
Avoid calling setState
multiple time in this case:
const { evc } = this.props;
if (evc.chargingStationGroups) {
let allIdArray = [];
evc.chargingStationGroups.forEach(item => {
allIdArray = [
...allIdArray,
...item.stations.map(stationItem => ({
stationId: stationItem.stationId
}))
];
});
this.setState({ stationIdArray: allIdArray });
}
A simple example: https://codesandbox.io/s/bold-swartz-leto5
Upvotes: 2
Reputation: 97
You should just use forEach if you want to do operations during iteration.
const { evc } = this.props;
evc.chargingStationGroups && evc.chargingStationGroups.forEach((item, key) => {
item.stations.forEach((stationItem, key) => {
console.log("stationID ",stationItem.stationID);
var stationId = {};
stationId = {
stationId: stationItem.stationID
}
var allIdArray = this.state.stationIdArray.concat(stationId);
this.setState({ stationIdArray: allIdArray })
})
})
Upvotes: 0
Reputation: 5703
Only call setState
once inside all your rendering (because setState
is asynchronous)
Assuming you don't have dupes of station between chargingStationGroups, just concat everybody
const { evc } = this.props;
if (evc.chargingStationGroups) {
const ids = evc.chargingStationGroups.flatMap((item, key) => {
return item.stations.map((stationItem, key) => {
return {
stationId: stationItem.stationID
}
})
})
const stationIdArray = this.state.stationIdArray.concat(ids)
this.setState({ stationIdArray })
})
Else just avoid the dupes...
const { evc } = this.props;
if (evc.chargingStationGroups) {
const ids = evc.chargingStationGroups.flatMap((item, key) => {
return item.stations.map((stationItem, key) => {
return {
stationId: stationItem.stationID
}
})
})
const arr = this.state.stationIdArray.concat(ids)
const s = new Set(arr.map(x => x.stationID))
const stationIdArray = [...s].map(stationId => ({ stationId }))
this.setState({ stationIdArray })
})
Not tested because no minimal reproducible example given, but you get the idea...
Upvotes: 2