如何在 "setUsername" 场景中最小化 firestore 读取?
How can I minimize firestore reads in the "setUsername" scenario?
我现在创建的代码正在运行,但我认为它在某种程度上不是最理想的,因为它对许多数据库读取都是如此
据我了解,“onAuthStateChange”可以理解为 useEffect 挂钩,每当用户身份验证状态发生变化(登录、注销)时都会调用它。每当发生这种情况时,都应检查数据库以查找用户选择的用户名。但是如果我看一下控制台,docSnap 会被记录很多次,这对我来说表明该函数被调用的次数比用户登录/注销时调用的次数更多。
上下文组件
import { createContext } from "react/cjs/react.production.min";
import { onAuthStateChanged } from "firebase/auth";
import { doc, getDoc } from "firebase/firestore";
import { auth,db } from "./firebase";
import { useState, useEffect } from "react";
export const authContext = createContext({
user: "null",
username: "null",
});
export default function AuthenticationContext(props) {
const [googleUser, setGoogleUser] = useState(null);
const [username, setUsername] = useState(null);
const [userID, setUserID] = useState(null);
onAuthStateChanged(auth, (user) => {
if (user) {
setGoogleUser(user.displayName);
setUserID(user.uid);
getUsername();
} else {
setGoogleUser(null);
}
});
const getUsername = async () => {
const docRef = doc(db, `users/${userID}`);
const docSnap = await getDoc(docRef);
if(docSnap.exists()){
setUsername(docSnap.data().username);
}
else{
setUsername(null);
}
};
return (
<authContext.Provider value={{ user: googleUser, username: username }}>
{props.children}
</authContext.Provider>
);
}
更重要的是,当我使用 google 登录并提交用户名时,组件不会重新评估 - 因此需要刷新才能使所有更改生效,这有一些问题与我不更新登录页面的 submitHandler 中的状态有关。如果您对我如何更专业地做到这一点有一些想法,请告诉我。提前致谢!
在登录页面提交处理程序
const submitHandler = async (event) => {
event.preventDefault();
console.log(auth.lastNotifiedUid);
await setDoc(doc(db, "users", auth.lastNotifiedUid), {
displayName: user,
username: username,
});
await setDoc(doc(db, "usernames", username), { uid: auth.lastNotifiedUid });
};
正如 Dharmaraj 在评论中指出的那样,您将多个订阅设置为身份验证状态。这是因为您在组件主体中调用了 onAuthStateChanged
,因此它会在每次渲染时执行。
为避免这种情况,您应该将函数包装在 useEffect
中,以便您只订阅组件安装,并在卸载时取消订阅:
export default function AuthenticationContext(props) {
/* ... */
React.useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, (user) => { /* ... */ });
return unsubscribe;
}, []);
/* ... */
}
我现在创建的代码正在运行,但我认为它在某种程度上不是最理想的,因为它对许多数据库读取都是如此 据我了解,“onAuthStateChange”可以理解为 useEffect 挂钩,每当用户身份验证状态发生变化(登录、注销)时都会调用它。每当发生这种情况时,都应检查数据库以查找用户选择的用户名。但是如果我看一下控制台,docSnap 会被记录很多次,这对我来说表明该函数被调用的次数比用户登录/注销时调用的次数更多。
上下文组件
import { createContext } from "react/cjs/react.production.min";
import { onAuthStateChanged } from "firebase/auth";
import { doc, getDoc } from "firebase/firestore";
import { auth,db } from "./firebase";
import { useState, useEffect } from "react";
export const authContext = createContext({
user: "null",
username: "null",
});
export default function AuthenticationContext(props) {
const [googleUser, setGoogleUser] = useState(null);
const [username, setUsername] = useState(null);
const [userID, setUserID] = useState(null);
onAuthStateChanged(auth, (user) => {
if (user) {
setGoogleUser(user.displayName);
setUserID(user.uid);
getUsername();
} else {
setGoogleUser(null);
}
});
const getUsername = async () => {
const docRef = doc(db, `users/${userID}`);
const docSnap = await getDoc(docRef);
if(docSnap.exists()){
setUsername(docSnap.data().username);
}
else{
setUsername(null);
}
};
return (
<authContext.Provider value={{ user: googleUser, username: username }}>
{props.children}
</authContext.Provider>
);
}
更重要的是,当我使用 google 登录并提交用户名时,组件不会重新评估 - 因此需要刷新才能使所有更改生效,这有一些问题与我不更新登录页面的 submitHandler 中的状态有关。如果您对我如何更专业地做到这一点有一些想法,请告诉我。提前致谢!
在登录页面提交处理程序
const submitHandler = async (event) => {
event.preventDefault();
console.log(auth.lastNotifiedUid);
await setDoc(doc(db, "users", auth.lastNotifiedUid), {
displayName: user,
username: username,
});
await setDoc(doc(db, "usernames", username), { uid: auth.lastNotifiedUid });
};
正如 Dharmaraj 在评论中指出的那样,您将多个订阅设置为身份验证状态。这是因为您在组件主体中调用了 onAuthStateChanged
,因此它会在每次渲染时执行。
为避免这种情况,您应该将函数包装在 useEffect
中,以便您只订阅组件安装,并在卸载时取消订阅:
export default function AuthenticationContext(props) {
/* ... */
React.useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, (user) => { /* ... */ });
return unsubscribe;
}, []);
/* ... */
}