1

I want to get my data with two nested database query after taking the whole daha with this process. I want to set it into my useState but useState always set []. I know that this is about async process but how can I fix it?

 useEffect(() => {
        const subscriber = firebase
          .firestore()
          .collection("Users")
          .doc(firebase.auth().currentUser.uid)
          .onSnapshot((querySnapshot) => {
            const followers = [];
            querySnapshot.data()["followers"].forEach(async (data) => {
              const fuser = await firebase
                .firestore()
                .collection("Users")
                .doc(data["uid"])
                .get();
              followers.push({
                name: fuser.data()["name"],
                nickname: fuser.data()["nickname"],
                surname: fuser.data()["surname"],
                profilePhotoURL: fuser.data()["profilePhotoURL"],
                key: fuser.id,
              });
    
              console.log(followers, "1"); // and second execute that
            });
            setFollowers(followers); // It always set []
            console.log(followers, "2"); //First execute that
            setLoading(false);
          });
isherwood
  • 58,414
  • 16
  • 114
  • 157
Leo S
  • 319
  • 2
  • 16
  • Does this answer your question? [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – Emile Bergeron Feb 15 '21 at 22:13

1 Answers1

2

The problem is that calling .forEach with an async function won’t wait for the function to finish for each element before moving to the next line.

As a consequence, your setState is executed before the followers array is filled. To fix this issue, use .map instead of .forEach, and wrap your “loop” inside a Promise.all:

.onSnapshot(async (querySnapshot) => { // you need the `async` here

  const followers = await Promise.all(
    querySnapshot.data()["followers"].map(async (data) => {
      const fuser = await firebase
        .firestore()
        .collection("Users")
        .doc(data["uid"])
        .get();
      return {
        name: fuser.data()["name"],
        nickname: fuser.data()["nickname"],
        surname: fuser.data()["surname"],
        profilePhotoURL: fuser.data()["profilePhotoURL"],
        key: fuser.id,
      }
    })
  );
  
  setFollowers(followers);
  // ...