【发布时间】:2022-01-03 05:19:48
【问题描述】:
我正在尝试使用 Firebase 在我的 React 应用中设置用户状态。
每次用户登录应用程序时,我都会将其保存为 users 集合,并在我的应用程序中显示为列表。
我需要显示每个用户的在线状态,所以我使用 Firebase Realtime db 来更新 Firestore db,这是整个 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,
};
}
users 集合中的 online 字段在我登录和注销时会更新,但在我关闭浏览器选项卡时不会更新,当我取消注释这部分时它有点工作:
onDisconnect(myConnectionsRef)
.set("disconnected")
.then(() => {
updateFirestoreUser(user, false);
});
但更改仅反映在 Realtime db 中,Firestore db users 集合中没有更改,字符串“disconnected”已添加到 Realtime 数据库中,但用户条目中没有任何更改我要在 @ 中更新987654329@方法。
在这里卡了2天,我不知道自己做错了什么,我只需要打开应用程序并登录用户时online字段为true,以及@987654332 @当用户退出或在浏览器中关闭应用时。
【问题讨论】:
-
您是否实现了 Cloud Functions,如下所示? firebase.google.com/docs/firestore/solutions/…
-
@FrankvanPuffelen 我没有找到关于它的 v9 文档,所以我无法按照您提供的链接执行此操作,而是按照此处的文档进行操作:firebase.google.com/docs/database/web/…
-
该链接显示了如何将存在信息获取到实时数据库中。如果没有我链接的 Cloud Functions 实现,就无法将状态信息从 RTDB 获取到 Firestore。
标签: reactjs firebase firebase-realtime-database google-cloud-firestore