2

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.

Nick Parsons
  • 45,728
  • 6
  • 46
  • 64
CraZyDroiD
  • 6,622
  • 30
  • 95
  • 182
  • 1
    Do not use `.map` for simple iteration. You are not doing a mapping operation, so it's not the correct tool for the job. – VLAZ Dec 23 '19 at 08:11
  • How else can i add all the stationId to my array? – CraZyDroiD Dec 23 '19 at 08:13
  • are you sure about station10, it seems to be in both groups? do you accept dupplicates in your array? – grodzi Dec 23 '19 at 08:15
  • If you are unsure what array iteration method is fit for each job, then click on my profile and check my bio. I've written a short guide. – VLAZ Dec 23 '19 at 08:19

3 Answers3

2

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...

grodzi
  • 5,633
  • 1
  • 15
  • 15
2

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

blaz
  • 3,981
  • 22
  • 37
  • Point about batched `setState` use is a really nice catch. Though there's a bit [shorter way](https://stackoverflow.com/a/59452046/11299053) to extract nested object prop. However, I think this one is more helpful than accepted answer. – Yevhen Horbunkov Dec 23 '19 at 08:37
0

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 })
    })
})