React+FirebaseStore使用signInWithRedirect无法创建docSnap问题
问题原因及解决方案
你遇到的核心问题是**signInWithRedirect的工作机制和signInWithPopup完全不同**:
调用signInWithRedirect后,浏览器会跳转到谷歌的授权页面,授权完成后再跳转回你的应用。这意味着你写在signInWithRedirect之后的所有代码(比如console.log(resultRef.user)、检查数据库、跳转页面)根本不会执行——因为原页面已经被销毁了,跳转回来后是重新加载的新页面。
而signInWithPopup是在当前页面弹出授权窗口,页面不会刷新,所以后续代码能正常运行。
修正步骤
- 简化移动端登录函数:只负责触发重定向,不做后续处理
- 在页面加载时处理重定向结果:用
getRedirectResult获取登录信息,再执行数据库检查和跳转逻辑 - 修复
useEffect的无限循环问题:添加正确的依赖项
修改后的代码示例
1. 调整onGoogleSignIn函数
async function onGoogleSignIn() { try { const auth = getAuth(); const provider = new GoogleAuthProvider(); if (isMobile) { // 移动端只触发重定向,后续逻辑交给useEffect处理 await signInWithRedirect(auth, provider); } else { // 桌面端popup逻辑保持不变 const resultRef = await signInWithPopup(auth, provider); const user = resultRef.user; const data = { uid: user.uid, email: user.email, verified: false, name: user.displayName, }; userData(data); const docRef = doc(db, "users", user.uid); const docSnap = await getDoc(docRef); if (!docSnap.exists()) { await setDoc(docRef, { displayName: user.displayName, email: user.email, uid: user.uid, timestamp: serverTimestamp(), }); navigate("/additional-info"); } else { // 已有用户文档,根据验证状态跳转 const userDoc = docSnap.data(); navigate(userDoc.verified ? "/" : "/additional-info"); } } } catch (error) { toast.error("Could not sign in with google"); console.log(error); } }
2. 重构useEffect处理重定向和状态监听
useEffect(() => { const auth = getAuth(); // 处理重定向登录的结果 const handleRedirectLogin = async () => { try { const result = await getRedirectResult(auth); if (result) { const user = result.user; const data = { uid: user.uid, email: user.email, verified: false, name: user.displayName, }; userData(data); // 检查数据库是否存在用户文档 const docRef = doc(db, "users", user.uid); const docSnap = await getDoc(docRef); if (!docSnap.exists()) { // 创建新文档并跳转到补充信息页 await setDoc(docRef, { displayName: user.displayName, email: user.email, uid: user.uid, timestamp: serverTimestamp(), }); navigate("/additional-info"); } else { // 已有文档,根据验证状态跳转 const userDoc = docSnap.data(); navigate(userDoc.verified ? "/" : "/additional-info"); } } } catch (error) { console.error("重定向登录处理失败:", error); toast.error("登录失败,请重试"); } }; // 监听用户状态变化(处理页面刷新后的持久化登录) const unsubscribe = onAuthStateChanged(auth, async (user) => { if (user) { const data = { uid: user.uid, email: user.email, verified: false, name: user.displayName, }; userData(data); // 检查用户文档状态 const docRef = doc(db, "users", user.uid); const docSnap = await getDoc(docRef); if (docSnap.exists()) { const userDoc = docSnap.data(); navigate(userDoc.verified ? "/" : "/additional-info"); } } }); // 页面加载时先处理重定向结果 handleRedirectLogin(); // 组件卸载时取消监听 return () => unsubscribe(); }, [navigate, userData]); // 添加依赖项,避免无限循环
额外注意点
- 原代码中
useEffect没有依赖项,会导致组件每次渲染都重新执行,引发无限循环,必须加上navigate和userData作为依赖 - 不要在
signInWithRedirect之后写任何逻辑,因为这些代码永远不会被执行 - 重定向后的页面加载时,
getRedirectResult会返回登录结果,如果用户已经登录过(比如刷新页面),则onAuthStateChanged会触发,处理持久化登录状态
内容的提问来源于stack exchange,提问作者saj aytaan
相关产品推荐
相关产品推荐

