Home > database >  Fetching data in a loop and then calling setState not working in React
Fetching data in a loop and then calling setState not working in React

Time:12-13

I am working with React, and I have a component that gets data from Firebase, which is a list of movies the user has watched.

After getting that data, I loop through that individual movie and get data of the movie. This all happens when the component mount:

useEffect(() => {
  getWatched();
}, []);

And getWatched is the function that gets all the data:

const getWatched = async () => {
  try {
    const snapShot = await getDocs(
      collection(db, "users", auth.currentUser.uid, "Watched")
    );
    let arr = [];
    snapShot.forEach((doc) => {
      arr.push(doc.data());
    });
    let w = [];
    arr.forEach((obj) => {
      let show = obj.show ? "movie" : "tv";
      console.log(obj.id);
      const link =
        "https://api.themoviedb.org/3/"  
        show  
        "/"  
        obj.id  
        "?api_key="  
        process.env.REACT_APP_MOVIE_DB  
        "&language=en-US";
      fetch(link)
        .then((response) => response.json())
        .then((response) => w.push(response));
    });
    setWatched(w);
    console.log("Got Data");
  } catch (error) {
    console.log(error);
  }
};

And in the return, I am looping through watched and returning divs of the data I have got. I guess I am getting data late. So it is not showing me anything.

CodePudding user response:

It's because setWatched(w) is being called before the promises resolve. A solution to this is to use a Promise.all() like so:

const getWatched = async () => {
  const innerFetch = async (link) => {
    const res = await fetch(link);
    const data = await res.json();
    return data;
  };
  try {
    const snapShot = await getDocs(
      collection(db, "users", auth.currentUser.uid, "Watched")
    );
    const arr = [];
    snapShot.forEach((doc) => {
      arr.push(doc.data());
    });

    const promises = arr.map((obj) => {
      let show = obj.show ? "movie" : "tv";
      console.log(obj.id);
      const link =
        "https://api.themoviedb.org/3/"  
        show  
        "/"  
        obj.id  
        "?api_key="  
        process.env.REACT_APP_MOVIE_DB  
        "&language=en-US";
      return innerFetch(link);
    });

    const w = await Promise.all(promises);
    setWatched(w);
    console.log("Got Data");
  } catch (error) {
    console.log(error);
  }
};

CodePudding user response:

I am satisfied with yousoumar answer. Here I have also tried something.

const getWatched = async () => {
        try {
            const snapShot = await getDocs(collection(db, "users", auth.currentUser.uid, "Watched"));
            let arr = [];
            snapShot.forEach((doc) => {
                arr.push(doc.data());
            })
            let w = [];
            arr.forEach((obj) => {
                let show = obj.show ? "movie" : "tv";
                const link = "https://api.themoviedb.org/3/"   show   "/"  
                    obj.id   "?api_key="   process.env.REACT_APP_MOVIE_DB   "&language=en-US";
                w.push(getData(link));
            });
            Promise.all(w)
                .then(results => {
                    setWatched(results);
                })
                .catch((err) => console.log(err));
        } catch (error) {
            console.log(error);
        }
    }

The main idea here as yousoumar said is using Promise.all.

  • Related