Home > OS >  Setting state only working after rerender
Setting state only working after rerender

Time:09-06

I have this Firebase Firestore query set up in my useEffect hook:

const [favorites, setFavorites] = useState([]);
const { user, setUser } = useContext(AuthenticatedUserContext);

  const getUserFavorites = async () => {
    const favoritesRef = collection(db, "favorites");
    const q = query(favoritesRef, where("userId", "==", user.uid));
    const querySnapshot = await getDocs(q);
    const fetchedFavorites = [];
    querySnapshot.forEach(async (document) => {
      const docRef = doc(db, "receipes", document.data().recipeId);
      const docSnap = await getDoc(docRef);
      const data = docSnap.data();
      fetchedFavorites.push(data);
    });
    setFavorites(fetchedFavorites);
    console.log("favorites "   favorites);
  };

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

Upon first render of the page the favorites will be [] and after a re-render it will be populated. When logging within the forEach I can see that the query is working, so I suspect the async forEach being the culprit here. How can I fix this?

CodePudding user response:

Yes, you should not use async function with a forEach() loop. You can use a for-of loop with the same code or use Promise.all() as shown below:

const getUserFavorites = async () => {
  const favoritesRef = collection(db, "favorites");
  const q = query(favoritesRef, where("userId", "==", user.uid));
  const querySnapshot = await getDocs(q);

  const favPromises = querySnapshot.docs.map((d) => getDoc(doc(db, "receipes", d.data().recipeId)))
  const fetchedFavs = (await Promise.all(favPromises)).map((fav) => fav.data());

  setFavorites(fetchedFavs);
  console.log("favorites "   fetchedFavs);
};

Also checkout: Using async/await with a forEach loop for more information.

  • Related