在 React 中使用 Firestore 数据库和 Firebase Realtime 数据库实现用户状态

问题描述 投票:0回答:2

我正在尝试使用 Firebase 在我的 React 应用程序中设置用户状态。 每次用户登录应用程序时,我都会将其保存为

users
集合,并将其显示为我的应用程序中的列表。

我需要显示每个用户的在线状态,因此我使用 Firebase Realtime 数据库来更新 Firestore 数据库,这是整个 AuthContext.js 文件:

import React, { useState, useEffect, useContext, createContext } from "react";
import { db, rtdb } from "../firebase/firebase-config";
import {
  getAuth,
  signInWithPopup,
  GoogleAuthProvider,
  onAuthStateChanged,
  signOut,
} from "firebase/auth";
import {
  addDoc,
  collection,
  serverTimestamp,
  getDocs,
  query,
  where,
  limit,
  updateDoc,
  doc,
} from "firebase/firestore";
import { Redirect } from "react-router-dom";
import { ref as rtdbRef, set, onValue } from "firebase/database";

const authContext = createContext();

export function ProvideAuth({ children }) {
  const auth = useProvideAuth();
  return <authContext.Provider value={auth}>{children}</authContext.Provider>;
}

export const useAuth = () => {
  return useContext(authContext);
};

function useProvideAuth() {
  const [user, setUser] = useState(null);
  const provider = new GoogleAuthProvider();
  const auth = getAuth();
  const [userLoading, setUserLoading] = useState(true);

  const getUserByUid = async (uid) => {
    let exists = false;
    const querySnapshot = await getDocs(
      query(collection(db, "users"), where("uid", "==", uid), limit(1))
    );
    querySnapshot.forEach(() => (exists = true));
    return exists;
  };

  const persistUser = async (user) => {
    const exists = await getUserByUid(user.uid);
    if (!exists) {
      await addDoc(collection(db, "users"), {
        uid: user.uid,
        displayName: user.displayName,
        email: user.email,
        photoURL: user.photoURL,
        createdAt: serverTimestamp(),
        updatedAt: null,
      });
    }
  };

  const logIn = () =>
    signInWithPopup(auth, provider)
      .then((result) => {
        setUser(result.user);
        persistUser(result.user);
      })
      .catch((err) => {
        console.log(err);
      });

  const updateFirestoreUser = (user, status) => {
    if (user) {
      getDocs(
        query(collection(db, "users"), where("uid", "==", user.uid), limit(1))
      ).then((querySnapshot) => {
        querySnapshot.forEach((u) => {
          updateDoc(doc(db, "users", u.id), {
            online: status,
            updatedAt: serverTimestamp(),
          });
        });
      });
    }
  };

  const logOut = () =>
    signOut(auth)
      .then(() => {
        console.log("SIGNOUT", user);
        updateFirestoreUser(user, false);
        setUser(false);
        return <Redirect to="/login" />;
      })
      .catch((err) => {
        console.log(err);
      });

  function checkAuthStatus() {
    return new Promise((resolve, reject) => {
      try {
        onAuthStateChanged(auth, async (user) => {
          resolve(user);
          setUser(user);

          const connectedRef = rtdbRef(rtdb, ".info/connected");
          const myConnectionsRef = rtdbRef(rtdb, `status`);
          onValue(connectedRef, (snap) => {
            if (snap.val() === true) {
              console.log("TRUE");
              if (user) {
                set(myConnectionsRef, "connected");
                updateFirestoreUser(user, true);
              }
            } else {
              console.log("FALSE");
              updateFirestoreUser(user, false);
            }
            //onDisconnect(myConnectionsRef)
              //.set("disconnected")
              //.then(() => {
              //   updateFirestoreUser(user, false);
              //});
          });
        });
      } catch {
        reject("api failed");
        setUser(false);
      }
    });
  }

  const getUser = async () => {
    setUserLoading(true);
    await checkAuthStatus();
    setUserLoading(false);
  };

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

  return {
    user,
    logIn,
    logOut,
    userLoading,
  };
}

当我登录和注销时,

online
集合中的
users
字段会更新,但当我关闭浏览器选项卡时不会更新,当我取消注释这部分时它会起作用:

onDisconnect(myConnectionsRef)
 .set("disconnected")
 .then(() => {
    updateFirestoreUser(user, false);
});

但是这些更改仅反映在实时数据库中,Firestore 数据库

users
集合中没有任何更改,字符串“disconnected”被添加到实时数据库中,但我要在
then()
中更新的用户条目中没有任何更改方法。

被困在这里2天了,我不知道我做错了什么,我只需要当应用程序打开并且用户登录时

online
字段为
true
,以及当用户登录时
false
用户已注销或应用程序在浏览器中已关闭。

reactjs firebase firebase-realtime-database google-cloud-firestore
2个回答
1
投票

通过遵循您链接的文档中的状态系统,您将在实时数据库中获取状态信息。

要将这些信息输入 Firestore,您需要实现一个在实时数据库写入中触发的云函数,如在 Firestore 上实现状态文档中的更新 Firestore 中的状态信息部分所示。这是在 Firestore 中获取状态信息的唯一方法,因为该数据库没有任何构建状态系统所需的

onDisconnect
之类的功能。


0
投票

我也在开发一个聊天应用程序,并想为其添加状态功能,但我和你一样遇到错误。 你能分享一下 rtdb 的代码吗,因为我收到了此导入中未定义的错误 从“../firebase/firebase-config”导入{ db, rtdb }; 如果您能分享代码,这对我真的很有帮助。

© www.soinside.com 2019 - 2024. All rights reserved.