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.

4
  • 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. Commented Dec 23, 2019 at 8:11
  • How else can i add all the stationId to my array? Commented Dec 23, 2019 at 8:13
  • are you sure about station10, it seems to be in both groups? do you accept dupplicates in your array? Commented Dec 23, 2019 at 8: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. Commented Dec 23, 2019 at 8:19

3 Answers 3

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

Sign up to request clarification or add additional context in comments.

Comments

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

1 Comment

Point about batched setState use is a really nice catch. Though there's a bit shorter way to extract nested object prop. However, I think this one is more helpful than accepted answer.
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 })
    })
})

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.