Firebase登出报Cannot read properties of null(reading 'uid')错误解决
报错原因
你将用户信息读取、Firestore文档引用初始化的逻辑写在了Logout自定义Hook的顶层作用域,这部分代码会在Hook挂载、所在组件每次重渲染时全量执行:
- 登出操作触发后,Firebase Auth会立刻将全局
auth.currentUser置为null,同时触发认证状态变更,App组件监听到用户为空后会切换到未认证路由,整个过程会触发关联组件重渲染 - 重渲染阶段顶层代码执行
const uid = user.uid时,auth.currentUser已经是null,直接触发Cannot read properties of null (reading 'uid')报错 - 功能表现正常是因为删除accessToken的异步操作在
signOut执行前已经提交,后续路由跳转逻辑也未被报错中断,只是重渲染阶段的空值读取触发了控制台错误。
修复方案
将所有依赖登录用户状态的逻辑移入logoutUser触发函数内部,同时增加空值兜底校验,避免未登录状态下的异常读取:
import { signOut } from "@firebase/auth"; import { useNavigate } from "react-router"; import { auth, db } from "../../firebase"; import { doc, updateDoc, deleteField } from "firebase/firestore"; export const Logout = () => { const navigate = useNavigate(); const logoutUser = async () => { const user = auth.currentUser; // 未登录状态直接跳转,不执行后续数据库操作 if (!user) { navigate("/"); return; } const uid = user.uid; const userRef = doc(db, 'users', uid); // 删除用户文档中存储的无过期API访问令牌 await updateDoc(userRef, { accessToken: deleteField() }); // 等待登出状态同步完成后再执行路由跳转 await signOut(auth); navigate("/"); } return {logoutUser} };
调整后只有用户主动点击登出触发logoutUser时,才会读取当前登录用户信息,不会在组件重渲染阶段提前读取可能为null的用户对象,从根源避免空值报错;同时将signOut改为await同步写法,解决了原代码中可能出现的登出状态和路由跳转时序不一致问题。
可选优化项
- 你在App组件中已经通过
useAuthState拿到了响应式的user对象,更推荐将该用户对象通过AppContext全局下发,业务代码中优先从Context获取用户信息,不要直接读取非响应式的auth.currentUser,避免出现状态不同步问题 - 登出按钮可增加认证状态判断,仅在用户确认处于登录状态时可点击,进一步减少异常触发场景
内容的提问来源于stack exchange,提问作者Michael Stubbs
相关产品推荐
相关产品推荐

