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

React中从Firestore获取当前用户数据失败的问题求助

问题:Firestore无法获取当前登录用户详情,返回undefined/null

我搭了一套注册/认证系统,注册时Firestore的users集合能正确存入name、bio、email、imgURL、uid等用户信息,但在React的portfolio页面获取当前登录用户详情时,返回值始终是undefined或null。试过直接用uid查文档、onAuthStateChanged监听、获取整个users集合(只能拿到所有用户,筛不出当前用户),都没解决。


相关代码片段

continueSignUp.jsx(存入用户信息到Firestore)

const ContinueSignUp = () => {
  const [file, setFile] = useState();
  const [url, setURL] = useState();
  const [name, setName] = useState('');
  const [bio, setBio] = useState('');

  let user = firebase.auth().currentUser;
  let uid = user.uid;
  let email = user.email;
  
  const hidePlaceholder = url ? { display: "none" } : {};
  const navigate = useNavigate();

  function handleChange(e) {
    if (e.target.files && e.target.files[0]) setFile(e.target.files[0]);
    setURL(URL.createObjectURL(e.target.files[0]));
  }

  async function handleUpload(e) {
    e.preventDefault();
    const path = `/images/${file.name}`;
    const ref = storage.ref(path);
    await ref.put(file);
    const url = await ref.getDownloadURL();
    setURL(url);
    setFile(null);
    console.log(file);

    if (name === "") {
      return;
    }
    const userRef = collection(db, "users");
    addDoc(userRef, { name, bio, url, uid, email })
      .then((response) => {
        console.log(response);
        navigate("/portfolio")
      })
      .catch((error) => console.log(error.message));
  }
}

portfolio.jsx(尝试获取用户信息)

const Portfolio = () => {
  const uid = firebase.auth().currentUser.uid;
  const currentUserProfile = firebase.firestore().collection("users").doc(uid);
  
  useEffect(() => {
    currentUserProfile.get().then((doc) => {
     const userName = doc.data().bio;
      console.log(uid);
    }).catch((err) => {console.log("Error in displaying Name!")})
  }, []);
}

*注:实际文档ID已替换为0

尝试获取全集合的代码

const [profile, setProfile] = useState(null);

useEffect(() => {
  getUserData();
}, []);

useEffect(() => {
  console.log(profile);
}, [profile]);

function getUserData() {
  const userRef = collection(db, "users");
  getDocs(userRef)
    .then((response) => {
      const user = response.docs.map((doc) => ({
        data: doc.data(),
        id: doc.id,
      }));
      console.log(response);
      setProfile(user);
    })
    .catch((error) => console.log(error.message));
}

console.log(profile)输出:

[{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
0: {data: {…}, id: '00000000000000000000'}
1: {data: {…}, id: '00000000000000000000'}
2: {data: {…}, id: '00000000000000000000'}
3: {data: {…}, id: '00000000000000000000'}
4: {data: {…}, id: '00000000000000000000'}
5: {data: {…}, id: '00000000000000000000'}
6: {data: {…}, id: '00000000000000000000'}
7: {data: {…}, id: '00000000000000000000'}
8: {data: {…}, id: '00000000000000000000'}

问题原因与解决方法

核心问题:文档ID不匹配

你用addDoc存入用户数据时,Firestore会自动生成随机文档ID,但在portfolio页面用doc(uid)查询时,是用用户uid作为文档ID查找的——两者完全不匹配,自然查不到数据。

解决步骤

  1. 修改存入逻辑:用用户uid作为文档ID
    把addDoc改成setDoc,指定文档ID为用户uid,后续查询就能直接通过uid定位文档:

    // 替换continueSignUp里的addDoc部分
    const userDocRef = doc(db, "users", uid); // 用uid作为文档ID
    setDoc(userDocRef, { name, bio, url, uid, email })
      .then((response) => {
        console.log(response);
        navigate("/portfolio")
      })
      .catch((error) => console.log(error.message));
    
  2. 修复portfolio页面的查询逻辑
    直接在组件顶层取firebase.auth().currentUser可能为null(auth还没初始化完成),必须用onAuthStateChanged监听用户状态:

    const Portfolio = () => {
      const [userProfile, setUserProfile] = useState(null);
      const navigate = useNavigate();
    
      useEffect(() => {
        const unsubscribe = firebase.auth().onAuthStateChanged(async (currentUser) => {
          if (currentUser) {
            // 用户已登录,查询对应文档
            const userDocRef = doc(db, "users", currentUser.uid);
            const docSnapshot = await getDoc(userDocRef);
            if (docSnapshot.exists()) {
              setUserProfile(docSnapshot.data());
              console.log(docSnapshot.data());
            } else {
              console.log("用户文档不存在");
            }
          } else {
            // 用户未登录,跳转到登录页
            navigate("/login");
          }
        });
    
        // 组件卸载时取消监听,避免内存泄漏
        return () => unsubscribe();
      }, [navigate]);
    
      return (
        <div>
          {userProfile ? (
            <div>
              <h1>{userProfile.name}</h1>
              <p>{userProfile.bio}</p>
              <img src={userProfile.url} alt="Profile" />
            </div>
          ) : (
            <p>加载中...</p>
          )}
        </div>
      );
    };
    

备用方案:不修改现有文档结构

如果暂时不想改已有的文档结构,可以通过where条件筛选uid匹配的文档:

// 在portfolio页面中用where查询
const querySnapshot = await getDocs(query(collection(db, "users"), where("uid", "==", currentUser.uid)));
if (!querySnapshot.empty) {
  const userData = querySnapshot.docs[0].data();
  setUserProfile(userData);
}

代码优化建议

  1. 封装Firebase操作
    把Firestore、Auth的操作封装成单独的工具函数,比如firebase/utils.js:

    export const saveUserProfile = async (uid, profileData) => {
      const userDocRef = doc(db, "users", uid);
      await setDoc(userDocRef, profileData);
    };
    
    export const getUserProfile = async (uid) => {
      const userDocRef = doc(db, "users", uid);
      const docSnapshot = await getDoc(userDocRef);
      return docSnapshot.exists() ? docSnapshot.data() : null;
    };
    

    组件代码会更简洁,也方便后续维护。

  2. 处理加载与错误状态
    在组件中添加加载状态和错误状态,提升用户体验:

    const [loading, setLoading] = useState(true);
    const [error, setError] = useState(null);
    
    useEffect(() => {
      const unsubscribe = firebase.auth().onAuthStateChanged(async (currentUser) => {
        setLoading(true);
        try {
          if (currentUser) {
            const profile = await getUserProfile(currentUser.uid);
            setUserProfile(profile);
          } else {
            navigate("/login");
          }
        } catch (err) {
          setError(err.message);
        } finally {
          setLoading(false);
        }
      });
    
      return () => unsubscribe();
    }, [navigate]);
    
    // 渲染时处理状态
    if (loading) return <p>加载中...</p>;
    if (error) return <p>出错了:{error}</p>;
    
  3. 表单验证优化
    在handleUpload中,除了判断name为空,还可以添加更多验证逻辑(比如bio长度、文件类型),同时给用户明确提示,而不是直接return。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 07:07:14