简体   繁体   English

在循环中获取数据然后调用 setState 在 React 中不起作用

[英]Fetching data in a loop and then calling setState not working in React

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.我正在使用 React,我有一个组件可以从 Firebase 获取数据,这是用户看过的电影列表。

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:getWatched就是获取所有数据的function:

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.在返回时,我正在循环查看并返回我所获得数据的 div。 I guess I am getting data late.我想我迟到了数据。 So it is not showing me anything.所以它没有向我展示任何东西。

It's because setWatched(w) is being called before the promises resolve.这是因为setWatched(w)在承诺解决之前被调用。 A solution to this is to use a Promise.all() like so:一个解决方案是像这样使用Promise.all()

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);
  }
};

I am satisfied with yousoumar answer.我对 yousoumar 的回答很满意。 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 .正如 yousoumar 所说,这里的主要思想是使用Promise.all

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM