在 useEffect React 中调用异步函数中的 Firebase v9 onSnapShot

Firebase v9 onSnapShot in async function while being called in useEffect React

我正在使用 Firebase v9,我正在构建一个聊天应用程序,我需要在调用 onSnapShot 获取聊天数据之前做一些异步工作:

      const getChat = async () => {
        // I need to await for user data before doing anything else.
        // I'll need some user data to build the query which
        // I'll be using in onSnapShot later on.
        const user = await getUserData();
        console.log(user);
        
        const collectionRef = collection(db, "messages");
        const q = query(
        collectionRef, where("user_id", "==", user.id), orderBy("createdAt"));
    
        const unsubscribe = onSnapshot(q, (snapshot) => {
          const data = snapshot.docs.map((doc) => {
            const entry = doc.data();
    
            return {
              id: doc.id,
              message: entry.message,
            };
          });
          setChatLines(data);
        });
    
        return unsubscribe;
      };

然后在useEffect中:

  useEffect(() => {

    const unsubscribe = getChat();

    return () => {
      unsubscribe();
    };
  }, []);

这里的问题是 unsubsribe 是一个承诺,因为 getChat 是异步的,但我仍然想在调用 onSnapShot 之前等待 getUserData(),因为我需要稍后在 onSnapShot 查询中的用户数据。

有没有办法在 useEffect 清理函数中 unsubscribe 正确地完成这项工作?

在这种情况下,我建议使用 React ref 来保存要在 useEffect 清理函数中使用的取消订阅函数。

const unsubscribeRef = React.useRef();

const getChat = async () => {
  const user = await getUserData();
   
  const collectionRef = collection(db, "messages");
  const q = query(
  collectionRef, where("user_id", "==", user.id), orderBy("createdAt"));

  const unsubscribe = onSnapshot(q, (snapshot) => {
    const data = snapshot.docs.map((doc) => {
      const entry = doc.data();

      return {
        id: doc.id,
        message: entry.message,
      };
    });
    setChatLines(data);
  });

  unsubscribeRef.current = unsubscribe;
};

useEffect(() => {
  getChat();

  return () => {
    unsubscribeRef.current?.();
  };
}, []);

另一种方法是在 useEffect 挂钩回调主体中添加一个异步函数,它可以等待 getChat Promise 解析。

useEffect(() => {
  let unsubscribe;

  const getChatAndSubscribe = async () => {
    unsubscribe = await getChat();
  }
    
  getChatAndSubscribe();

  return () => {
    unsubscribe?.();
  };
}, []);