Search code examples
javascriptreactjsreact-hookses6-promise

How to modify useState array one by one in mapped promise


I have const [items, setItems] = useState<any[]>(itemsB.map(() => ({ loading: true }))); and

itemsB.map(async (itemB: any, index: number) => {
    searchItems(itemB).then(result => {
        const newItems = [...items]; // Ref A
        newItems[index] = result;
        setItems(newItems);
    })
})

Because the inner function is an async fetch, items come back in an unpredictable order, and I want to add them to items as soon as they're ready, changing the placeholder loading object with the actual result. This almost does that, but the items referenced at Ref A does not update, so it cycles through changing each thing and then at the end only the last item to have been retrieved appears.

If I do a Promise.all().then(), it waits until all items are retrieved to execute the then part, so I'm wondering how to set items as they are resolved.


Solution

  • The calls made to setItems are batched to optimize performance. If the previous state relies on the current state, use the overloaded version of setItems which takes the previousState as the first argument.

    searchItems(itemB).then(result => {
            setItems(items => {
                      const newItems = [...items]; // Ref A
                      newItems[index] = result;
                      return newItems;
            });
    })