CraZyDroiD
CraZyDroiD

Reputation: 7105

Only last item is added to array inside map function

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

Answers (3)

blaz
blaz

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

Zaw Hlaing Bwar
Zaw Hlaing Bwar

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

grodzi
grodzi

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

Related Questions