You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 11:30:48