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

React Context配合Firebase监听用户文档时login内currentUser返回null问题

问题原因

  • 你在login的then回调中直接读取currentUser状态时拿到旧值,是因为React状态更新是异步的:signInWithEmailAndPassword执行成功后,onAuthStateChanged监听器会触发setCurrentUser更新状态,但这个状态更新不会立刻同步到当前函数闭包中,所以你读取到的还是执行login函数时的初始null值。
  • 你当前把取消订阅函数存在state里的写法是可行的,但有逻辑遗漏:如果用户是刷新页面后保持的登录态,你没有触发用户文档的snapshot监听,另外注销时如果取消订阅函数为null会抛出调用错误。

修复方案

把用户文档的监听逻辑移到onAuthStateChanged的回调中,既能统一处理登录/刷新登录两种场景,也能直接拿到回调返回的最新用户对象,不需要依赖组件状态。

修正后的代码

import React, { useContext, useState, useEffect } from 'react'
import { auth, db } from '../init/firebase'

const AuthContext = React.createContext()

export function useAuth() {
  return useContext(AuthContext)
}

export function AuthProvider({ children }) {
  const [currentUser, setCurrentUser] = useState(null)
  const [loading, setLoading] = useState(true)

  // User firebase doc init
  const [userDoc, setUserDoc] = useState({
    loaded: false,
    data: [],
  })
  const [firebaseUnsubscriber, setFirebaseUnsubscriber] = useState(null);

  function signup(email, password) {
    return auth.createUserWithEmailAndPassword(email, password)
  }

  function login(email, password) {
    return auth.signInWithEmailAndPassword(email, password)
  }

  function logout() {
    return auth.signOut().then(() => {
      // 调用前先判断是否存在取消订阅函数
      if (firebaseUnsubscriber) {
        firebaseUnsubscriber();
        setFirebaseUnsubscriber(null);
      }
      // 清空用户文档状态
      setUserDoc({
        loaded: false,
        data: []
      })
    })
  }

  useEffect(() => {
    const unsubscriber = auth.onAuthStateChanged((user) => {
      setCurrentUser(user)
      // 先清理上一个用户的监听
      if (firebaseUnsubscriber) {
        firebaseUnsubscriber();
        setFirebaseUnsubscriber(null);
      }
      if (user) {
        // 直接用回调返回的user对象,不需要依赖state
        const unsub = db.collection("users").doc(user.uid).onSnapshot((doc) => {
          setUserDoc({
            loaded: true,
            data: doc.data(),
          })
        });
        setFirebaseUnsubscriber(unsub);
      }
      setLoading(false)
    })

    return () => {
      unsubscriber()
      // 组件卸载时清理用户文档监听
      if (firebaseUnsubscriber) {
        firebaseUnsubscriber();
      }
    }
  }, [firebaseUnsubscriber])

  const value = {
    currentUser,
    userDoc,
    login,
    signup,
    logout,
  }

  return (
    <AuthContext.Provider value={value}>
      {!loading && children}
    </AuthContext.Provider>
  )
}

内容的提问来源于stack exchange,提问作者No Sarcasm

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 08:27:00