Manuel Duarte
Manuel Duarte

Reputation: 1040

React Custom Hook and Firestore Snapshot

I created a React custom hook which listens to firestore database, i followed the documentation in firebase website but I'm having trouble when I re-render the component. When I refresh my app the useEffect hook runs correctly but the listener inside unsubscribe() method doesn't. Here is the full code of the hook.

It works fine when the code recompiles itself after I save something in a component (first-render), but when it re-renders it shows as it if was always loading but it never executes the listener. Hope you can help me!

import { db } from "initFirebase";
import { useEffect, useState } from "react";

interface Payment {
  name: string;
  email: string;
  phone: string;
  course: string;
  pagado: boolean;
}

export const usePaymentsCollection = () => {
  const [payments, setPayments] = useState<Payment[]>([]);
  const [isLoading, setIsLoading] = useState<boolean>(true);
  const [error, setError] = useState<any>(null);

  useEffect(() => {
    const unsubscribe = () => {
      try {
        db.collection("payments").onSnapshot(
          (snapshot) => {
            if (snapshot.docs.length) {
              console.log("simona");
              let allDocs: Payment[] = [];
              snapshot.docs.map((doc) => {
                console.log(doc.data());
                return allDocs.push(doc.data() as Payment);
              });
              setPayments(allDocs);
              setIsLoading(false);
            } else {
              console.log("isEmpty");
              setIsLoading(false);
            }
          },
          (error) => {
            // ...
          }
        );
      } catch (e) {
        setError(e);
      }
    };
    return () => unsubscribe();
  }, [db]);

  return {
    payments,
    isLoading,
    error,
  };
};

Upvotes: 0

Views: 731

Answers (1)

j1mbl3s
j1mbl3s

Reputation: 1028

The unsubscribe anonymous function you have provided is not a snapshot listener unsubscribe method. It is a function which creates a snapshot listener (and ignores the unsubscribe method returned from db.collection("payments").onSnapshot()).

You should set unsubscribe to the value returned from db.collection("payments").onSnapshot():

useEffect(() => {
  const unsubscribe = db.collection("payments").onSnapshot(
    (snapshot) => {
      // ...
    },
    (error) => {
      // ...
    }
  );
  return unsubscribe;
}, [db]);

Additionally, by passing the array [db] into the useEffect hook, it will run again on rerender when the db state/prop is updated. Be sure that this is what you want - it probably isn't, since db is likely not a state/prop.

Upvotes: 3

Related Questions