MatijaxD
MatijaxD

Reputation: 171

Is using setState in every iteration of a loop bad practice?

Here is a little code snippet:

async componentDidMount() {
    ...
    this.state.postList.forEach(element => {
      this.fetchItem(element);
    });
}

async fetchItem(query) {
    ...
    this.setState( previousState => {
        const list = [...previousState.data, data];
        return { data: list };
    });
}

I'm curious to know if using setState in every iteration of a forEach loop is a bad idea or not. I'm suspecting that it impacts performance, but I'd like to know for sure because this seemed like the simplest solution to this problem.

Upvotes: 5

Views: 425

Answers (2)

Jonas Wilms
Jonas Wilms

Reputation: 138267

I'm curious to know if using setState in every iteration of a forEach loop is a bad idea or not.

If it would be directly inside of an iteration then definetly yes, as React than has to merge all the updates you make during the iteration, which will probably take much more time than if you would just set the state after the loop. In your case however, you do start an asynchronous action in each iteration, and as all asynchronous tasks finish at different times, the updates aren't run all at once. The main benefit of your approach is that if these asynchronous tasks take some time (e.g. if you fetch a lot of data for each), then some information can already be shown, while some are still loading. If all those asynchronous calls only load a small amount of data, well then you should actually change your API to deliver all the data at once. So it really depends on your usecase wether thats good or bad.

Upvotes: 2

Arash Motamedi
Arash Motamedi

Reputation: 10682

Here's an alternative approach: Update your fetchItem to just return the item. In your componentDidMount use Promise.all to get all the items and then commit them to the state in a single operation.

async componentDidMount() {
    const items = await Promise.all(this.state.postList.map(element => fetchItem(element)));
    this.setState({data: items});
}

async fetchItem(query) {
    const item = await getItem(query) // however you accomplish this
    return item;
}

Upvotes: 5

Related Questions