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

React结合Firebase获取用户文档:刷新报错与数据获取失败问题

问题分析与解决方案

你遇到的问题核心是Firebase Auth的初始化是异步的:刷新页面时auth.currentUser和props.user都可能还没就绪,导致要么直接访问uid触发Cannot read property 'uid' of null报错,要么因为判断条件不满足无法执行数据库查询。

解决步骤

  1. 用onAuthStateChanged监听用户登录状态
    不要直接依赖auth.currentUser,而是用Firebase提供的onAuthStateChanged监听用户状态变化——它会在Auth初始化完成、用户登录/登出时触发回调,确保你能拿到有效的用户对象。
  2. 结合props.user和Auth状态,确保用户存在再查询
    同时监听props.user的变化,当props.user或Auth用户存在时,只要能拿到有效uid就执行数据库查询。
  3. 修复useEffect依赖项
    把props.user?.uid和auth加入依赖数组,确保状态变化时重新执行查询逻辑。

修改后的完整代码

import React, { useState, useEffect } from 'react'
import { doc, collection, getDocs, query, where } from "firebase/firestore";
import { getAuth, onAuthStateChanged } from "firebase/auth";
import { db } from "../firebaseConfig.js"
import { Link } from 'react-router-dom'

export default function ProfilePage(props) {
    const [username, setUsername] = useState("");
    const [name, setName] = useState("Jonah Park");
    const [major, setMajor] = useState("Computer Science");
    const [bio, setBio] = useState("I am a third-year CS student that loves to play volleyball and run in my free time!");
    const [schedule, setSchedule] = useState([]);
    const [profilePicture, setProfilePicture] = useState();
    const [userData, setUserData] = useState([]);
    const [isAuthLoaded, setIsAuthLoaded] = useState(false); // 标记Auth是否初始化完成

    const shadowStyle = {
        boxShadow: "0px 0px 6px 0px rgba(0,0,0,0.2)"
    }

    const userCollectionRef = collection(db, "users");
    const auth = getAuth();

    useEffect(() => {
        // 监听Auth状态变化
        const unsubscribe = onAuthStateChanged(auth, (user) => {
            setIsAuthLoaded(true); // Auth初始化完成
            // 优先用props传的uid,没有则用Auth用户的uid
            const targetUid = props.user?.uid || user?.uid;
            if (targetUid) {
                const getUsers = async () => {
                    let list = [];
                    try {
                        const q = query(userCollectionRef, where("uid", "==", targetUid));
                        const querySnapshot = await getDocs(q);
                        querySnapshot.forEach((doc) => {
                            list.push(doc.data());
                        });
                        setUserData(list);
                        // 拿到数据后同步更新组件状态
                        if (list.length > 0) {
                            setUsername(list[0].username);
                            setName(list[0].name);
                            setMajor(list[0].major);
                            setBio(list[0].bio);
                        }
                    } catch (err) {
                        console.log(err);
                    }
                }
                getUsers();
            }
        });

        // 组件卸载时取消监听,避免内存泄漏
        return () => unsubscribe();
    }, [props.user?.uid, auth]); // 依赖props.user的uid和auth对象

    // Auth未加载完成时显示加载提示
    if (!isAuthLoaded) {
        return <div>加载中...</div>;
    }

    return (
        <div style={shadowStyle}>
            <h1>{name}</h1>
            <p>用户名: {username}</p>
            <p>专业: {major}</p>
            <p>简介: {bio}</p>
            <Link to="/">返回首页</Link>
        </div>
    );
}

关键修改说明

  • 新增isAuthLoaded状态:标记Firebase Auth是否完成初始化,避免在Auth就绪前执行无效操作,同时给用户显示加载提示。
  • 使用onAuthStateChanged监听:解决了刷新页面时auth.currentUser为null的问题,确保在Auth状态稳定后再处理数据查询。
  • 兼容双来源uid:优先使用props.user.uid,没有则用Auth用户的uid,保证查询条件有效。
  • 清理监听:组件卸载时取消Auth状态监听,避免内存泄漏。
  • 数据同步更新:拿到数据库返回的用户数据后,直接同步更新组件的状态字段,无需额外逻辑。

内容的提问来源于stack exchange,提问作者Jonah Park

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 21:33:28