如何在初始渲染时检查Firebase Auth已登录用户?
Firebase Auth 初始渲染时 currentUser 为 null 的问题
我遇到一个问题:在应用初始渲染时,Firebase的auth.currentUser始终为null。登录登出功能正常,但useEffect中的初始渲染代码似乎在currentUser填充前执行。
组件简化代码:
import ... const [isInitialRender, setIsInitialRender] = useState(true); const firebaseConfig = {...} const app = initializeApp(firebaseConfig); // Auth export const auth = getAuth(); connectAuthEmulator(auth, "http://localhost:9099"); // Maybe part of the problem? // DB export const db = getFirestore(); connectFirestoreEmulator(db, "localhost", 8080); useEffect(() => { if (isInitialRender) { setIsInitialRender(() => false); //Attempt to check existing authentication if (auth.currentUser) console.log("Logged in"); // Never logs return; } if (auth.currentUser) console.log("Logged in"); // Works fine }
登录函数代码:
const signInWithGoogle = () => { const provider = new GoogleAuthProvider(); signInWithPopup(auth, provider) .then((result) => {}) .catch((error) => { const errorMessage = error.message; console.log("Google login encountered error:"); console.log(errorMessage); }); };
请问如何解决该问题?有没有更优的页面加载时检查认证状态的方法?
解决方案
1. 使用 onAuthStateChanged 监听认证状态
Firebase Auth 在初始化时需要异步加载用户的认证状态(从本地缓存或服务器同步),所以初始渲染时auth.currentUser还未被赋值。正确的做法是通过onAuthStateChanged订阅状态变化,这个回调会在初始加载完成以及登录/登出状态变化时触发。
修改后的useEffect代码示例:
useEffect(() => { // 订阅认证状态变化 const unsubscribe = onAuthStateChanged(auth, (user) => { if (user) { console.log("Logged in:", user); // 这里可以处理登录后的逻辑,比如跳转、设置用户状态等 } else { console.log("Not logged in"); // 处理未登录逻辑 } }); // 组件卸载时取消订阅,避免内存泄漏 return unsubscribe; }, []);
2. 避免重复初始化Firebase App
你的组件代码中每次渲染都会调用initializeApp(firebaseConfig),这会导致Firebase重复初始化报错。应该将Firebase初始化逻辑移到组件外部,或者用getApp()检查是否已初始化:
// 在组件外部初始化Firebase import { initializeApp, getApp, getApps } from "firebase/app"; import { getAuth, connectAuthEmulator, onAuthStateChanged } from "firebase/auth"; import { getFirestore, connectFirestoreEmulator } from "firebase/firestore"; const firebaseConfig = {...}; // 只初始化一次App const app = !getApps().length ? initializeApp(firebaseConfig) : getApp(); export const auth = getAuth(app); connectAuthEmulator(auth, "http://localhost:9099"); export const db = getFirestore(app); connectFirestoreEmulator(db, "localhost", 8080); // 组件内部代码 const YourComponent = () => { useEffect(() => { const unsubscribe = onAuthStateChanged(auth, (user) => { if (user) { console.log("Logged in"); } else { console.log("Not logged in"); } }); return unsubscribe; }, []); // ...其他组件逻辑 };
3. 关于模拟器的说明
使用connectAuthEmulator不会导致currentUser初始为null的问题,这个问题的核心是认证状态加载的异步性,和模拟器无关。
内容的提问来源于stack exchange,提问作者spheroidic
相关产品推荐
相关产品推荐

