React.js map loop with async Promise is infinite if surrounding Promise.all.then(response ... ) assigns response value
P粉895187266
P粉895187266 2023-09-14 16:02:55
0
1
448

I just ran into this problem and couldn't find any resources about my case. I'm building a React app that uses the Spotify API and want to execute a function that populates a local useState object with an "ArtistInformation" array (a js object from the API endpoint).

This code example iterates through the artist id array and should only execute the Api function "spotiApi.getArtistInfo(id)" once.

When run like this:

const getArtistInformation = () => {
    console.log("sp ids",spotifyArtistIds)
    Promise.all(spotifyArtistIds.map(id => {
      return spotiApi.getArtistInfo(id)
    })).then(respList => {
      // setArtistInfo(respList)
      console.log("artistInfo", artistInfo)})
  }

Code snippet runs fine and stops execution

But when "setArtistInfo" useState is called, the loop continues to execute infinitely

const getArtistInformation = () => {
    console.log("sp ids",spotifyArtistIds)
    Promise.all(spotifyArtistIds.map(id => {
      return spotiApi.getArtistInfo(id)
    })).then(respList => {
      setArtistInfo(respList)
      console.log("artistInfo", artistInfo)})
  }

The following is the entire component for reference:

import { Box } from "@mui/material";
import React, { useEffect, useState } from "react";
import { useSelector } from "react-redux";
import SpotifyApi from "../../api/SpotifyApi";

export const DashboardView = () => {
  const spotifyArtistIds = useSelector(state => state.member.spotifyArtistIds)

  const [artistInfo, setArtistInfo] = useState([])
  const [showId, setShowId] = useState(spotifyArtistIds[0])
  const spotiApi = new SpotifyApi();

  const getArtistInformation = () => {
    console.log("sp ids",spotifyArtistIds)
    Promise.all(spotifyArtistIds.map(id => {
      return spotiApi.getArtistInfo(id)
    })).then(respList => {
      // setArtistInfo(respList)
      console.log("artistInfo", artistInfo)})
  }
 

  const getThisArtistInfo = () => {
    console.log("art", artistInfo)
    return artistInfo.filter(info => info.data.id === showId)[0].data
  }
  
  useEffect(() => {
    getArtistInformation()
  })

  return (
    <Box>
      <h2>{getThisArtistInfo()?.name}'s Dashboard</h2>

    </Box>)
}

Thanks for any help in advance and hope we can figure this out!

P粉895187266
P粉895187266

reply all(1)
P粉819533564

The loop will not execute endlessly, and the component will re-render endlessly. This causes a re-render:

setArtistInfo(respList);

This is executed on every render :

useEffect(() => {
  getArtistInformation();
});

So each rendering will get the artist information, which will trigger a re-render, which will get the artist information, which will trigger a re-render, etc.

If the intent is to get artist information only on the first render, include an empty dependencies array:

useEffect(() => {
  getArtistInformation();
}, []); // <-- here
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template