Home > Software design >  Firestore data doesn't show up
Firestore data doesn't show up

Time:02-24

In my custom hook, I am getting all the images in firestore collection. That was working fine UNTIL I have tried to get also metadata's of images. When I added the getMetaData function, I can't set the data to state even the datas seem fine in an array. See the code please.

import { useState, useEffect } from "react";
import { firebaseFireStore } from "../firebase/config";
import { storage } from "../firebase/config";
import { ref, getMetadata } from "firebase/storage";

const useFirestore = (collection) => {
  const [docs, setDocs] = useState([]);

  useEffect(() => {
    const unsub = firebaseFireStore
      .collection(collection)
      .onSnapshot((snap) => {
        let documents = [];
        snap.forEach((doc) => {
          const forestRef = ref(storage, doc.data().url);
          getMetadata(forestRef)
            .then((metadata) => {
              documents.push({ ...doc.data(), metadata, id: doc.id });
              return documents;
            })
            .catch((error) => {
              console.log(error);
            });
        });
        setDocs(documents);
        console.log(docs); // [] EMPTY ARRAY, PROBLEM IS HERE.
        console.log(documents); // [] length:13 data is complete inside.  
      });

    return () => unsub();
    // this is a cleanup function that react will run when
    // a component using the hook unmounts
  }, []);

  return { docs };
};

export default useFirestore;

So, even if documents array has the data with metadata in it, it can't be set to state of docs. Any help appreciated.

CodePudding user response:

You can't log the docs state right after enqueueing a state update since React asynchronously processes the state updates. But this isn't exactly your issue or what you are actually trying to solve. The code is mapping over the snapshot and enqueueing an asynchronous request to retrieve metadata and asynchronously mutating the documents array that was updated in React a long* time ago. The console.log(documents) is just exposing this mutation later when the browser is processing the log buffer.

To resolve I suggest declaring the snapshot.forEach callback async so it can wait for the getMetadata call to resolve. Use a functional state update to shallow merge each document as it resolves with metadata.

Example:

useEffect(() => {
  const unsubscribe = firebaseFireStore
    .collection(collection)
    .onSnapshot((snap) => {
      snap.forEach(async (doc) => {
        try {
          const forestRef = ref(storage, doc.data().url);
          const metadata = await getMetadata(forestRef);
          setDocs(documents => [
            ...documents,
            { ...doc.data(), metadata, id: doc.id }
          ]);
        } catch(error) {
          console.log(error);
        };
      });  
    });

  return unsubscribe;
}, []);

* "Long time ago" -> some previous render cycle.

  • Related