React集成Firebase Auth时已登录状态不被Header组件识别问题
问题根源
你当前的写法是同步获取 firebase.auth().currentUser,这是问题的核心原因:
- Firebase Auth 的初始化、本地持久化登录状态的恢复流程是异步执行的,Header 组件首次渲染时,Auth 还没有完成状态同步,此时读取
currentUser必然返回 null - 现有组件没有监听登录状态的变更事件,即使用户后续完成登录,组件也不会触发重新渲染,会一直保持首次渲染时的无登录判定结果
之前单页应用阶段未触发问题,大概率是登录流程的执行时机早于 Header 组件的渲染时机,架构调整后渲染时机、页面刷新逻辑发生变化,就暴露了这个逻辑缺陷。
解决方案
通过 React 的状态钩子 + Firebase 提供的登录状态监听器改造组件:
- 用
useState存储用户登录状态,驱动组件渲染 - 用
useEffect绑定onAuthStateChanged监听器,登录状态变更时自动更新状态、触发重渲染 - 将用户对象通过 props 透传给 Dropdown 组件,避免多处取值出现状态不一致
修改后代码
import firebase from 'firebase/app'; import 'firebase/firestore'; import 'firebase/auth'; import React, { useState, useEffect } from 'react' import SignIn from "./SignIn"; import SignOut from "./SignOut"; // 接收父组件传的user作为props,不再单独取值 function Dropdown({user}) { return ( <li class="nav-item dropdown"> <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false"> {user.displayName} </a> <ul class="dropdown-menu" aria-labelledby="navbarDropdown"> <li><a class="dropdown-item" href="/profile">My facts</a></li> <li><a class="dropdown-item" href="#">Admin</a></li> <li><hr class="dropdown-divider" /></li> <li><SignOut class="dropdown-item btn btn-link text-dark" /></li> </ul> </li> ) } function Header() { // 用state存储用户状态 const [user, setUser] = useState(null); // 可选:添加加载态,避免登录状态切换时的UI闪烁 const [authLoading, setAuthLoading] = useState(true); const handelSubmit = (e) => { e.preventDefault(); } useEffect(() => { // 绑定登录状态监听器 const unsubscribe = firebase.auth().onAuthStateChanged((currentUser) => { setUser(currentUser); setAuthLoading(false); }); // 组件卸载时取消监听,避免内存泄漏 return () => unsubscribe(); }, []) // 认证过程中可以渲染加载占位,也可以直接返回null if(authLoading) return <nav class="navbar navbar-expand-lg sticky-top navbar-light bg-light"><div class="container-fluid">加载中...</div></nav> return ( <nav class="navbar navbar-expand-lg sticky-top navbar-light bg-light"> <div class="container-fluid"> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarTogglerDemo03" aria-controls="navbarTogglerDemo03" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <a class="navbar-brand" href="#">Cool Cow Facts</a> <div class="collapse navbar-collapse" id="navbarTogglerDemo03"> <ul class="navbar-nav me-auto mb-2 mb-lg-0"> <li class="nav-item"> <a class="nav-link active" aria-current="page" href="./">Home</a> </li> <li class="nav-item"> <button type="button" class="btn btn-link nav-link active" data-bs-toggle="modal" data-bs-target="#exampleModal"> Submit Fact </button> </li> </ul> <form onSubmit={handelSubmit}> <ul class="navbar-nav me-auto mb-2 mb-lg-0"> { user ? <Dropdown user={user} /> : <SignIn class="btn btn-link nav-link active text-dark" message="Sign In" /> } </ul> </form> </div> </div> </nav> ) } export default Header
内容的提问来源于stack exchange,提问作者Cool cow facts
相关产品推荐
相关产品推荐

