Проблемы, касающиеся моего пользовательского крючка React для прослушивания Firestore в реальном времени, может ли этот пользовательский крючок создать несколько слушателей?

# #reactjs #firebase #google-cloud-firestore #react-hooks

Вопрос:

Мне любопытно, может ли кто-нибудь помочь мне с моим пользовательским крючком, который прослушивает данные в реальном времени из Firestore.

В некотором контексте пользовательский крючок предназначен для уведомлений, которые должны срабатывать при добавлении нового документа в коллекцию notifications_history пользователя в Firestore. Я хочу, чтобы это были уведомления, которые они действительно получили после того, как отрисовали страницу, поэтому я заказываю их по их временной метке createdAt, и я также проверяю, чтобы они были созданы после временной метки, которую я создаю при первоначальной отрисовке. (Для этого я использую крючок useRef)

Пользовательский хук имеет эффект использования, для которого требуется идентификатор пользователя, прошедшего проверку подлинности, и я не смог придумать никакого другого решения, кроме добавления идентификатора uid в массив зависимостей эффекта использования, поскольку пользователь изначально не определен. Однако я не могу избавиться от ощущения, что делаю что-то не так, и что есть лучшее решение.

Одна из моих проблем заключается в том, что, поскольку эффект использования имеет пользователя в качестве зависимости, то, возможно, это может создать несколько прослушивателей в случае возникновения некоторых проблем с аутентификацией?

Еще одна моя проблема, которая, как я полагаю, связана с реакцией, заключается в том, могу ли я каким-либо образом сделать так, чтобы я передавал uid в качестве опоры для крючка только тогда, когда на самом деле есть uid? Это действительно решило бы вышеперечисленные проблемы так!

Вот код:

 import { useEffect, useRef, useState } from "react";

import { clientFirestore } from "@/frontend/client/firebase";

import {
  collection,
  query,
  limit,
  orderBy,
  where,
  onSnapshot,
} from "firebase/firestore";

import { useAuth } from "./useAuth";

const useNotification = () => {
  const timeRef = useRef(Date.now());

  const { user } = useAuth();
  const uid = user?.uid;

  const [data, setData] = useState({
    error: null,
    loading: true,
    notification: null,
  });

  useEffect(() => {
    if (!uid) return;

    const notificationQuery = query(
      collection(clientFirestore, `users/${uid}/notification_history`),
      orderBy("createdAt"),
      where("createdAt", ">=", timeRef.current),
      limit(1)
    );

    const unsubscribe = onSnapshot(
      notificationQuery,
      (snapshot) => {
        let newNotification;
        snapshot.forEach((doc) => {
          const docData = doc.data();
          if (doc amp;amp; docData) {
            newNotification = {
              id: doc.id,
              message: docData.message,
              createdAt: docData.createdAt,
            };
          }
        });
        setData({
          error: null,
          loading: false,
          notification: newNotification,
        });
      },
      (error) => {
        setData({
          error,
          loading: false,
          notification: null,
        });
        console.log(error);
      }
    );

    return unsubscribe;
  }, [uid]);

  return data;
};

export default useNotification;

.
.
.

in another file:

const data = useNotification();

 useEffect(() => {
    if (data amp;amp; data.notification) {
      toast.success(data.notification.message);
      playSound();
    }
 }, [data]);