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

React使用Firebase V9开发自定义Hook时新建用户文档后username设置问题

问题根因

核心错误出在新建文档后的赋值逻辑:当判断docSnap.exists()为false时,你首次调用getDoc拿到的快照本身就没有数据,此时调用docSnap.data()返回值为undefined,自然无法正确给username状态赋值。

修复方案

推荐直接统一使用onSnapshot监听文档,该方法会自动触发首次数据拉取,后续文档新建、更新操作也会自动同步回调,不用拆分判断逻辑,代码更简洁也不会出现状态同步问题,修复后代码如下:

import { auth, firestore } from './firebase-config';
import {
  doc,
  onSnapshot,
  setDoc,
} from '@firebase/firestore';
import { useEffect, useState } from 'react';
import { useAuthState } from 'react-firebase-hooks/auth';

// 自定义Hook:读取认证状态和用户档案文档
export function useUserData() {
  const [user] = useAuthState(auth);
  const [username, setUsername] = useState(null);

  useEffect(() => {
    let unsubscribe;

    if (user) {
      const documentRef = doc(firestore, 'users', user.uid);
      
      // 统一开启快照监听,自动同步所有文档变更
      unsubscribe = onSnapshot(documentRef, async (doc) => {
        if (doc.exists()) {
          setUsername(doc.data().username);
        } else {
          // 文档不存在时新建
          await setDoc(documentRef, {
            name: user.displayName,
            email: user.email,
            username: user.displayName,
          });
          // 新建后无需手动赋值,onSnapshot会监听到新建的文档自动触发回调更新状态
        }
      });
    } else {
      setUsername(null);
    }

    return unsubscribe;
  }, [user]);

  return { user, username };
}

如果要保留原有代码结构不想调整逻辑,也可以直接在新建文档后,用写入数据库的用户名直接赋值即可:

// 原else分支修改为
else {
  const newUserInfo = {
    name: user.displayName,
    email: user.email,
    username: user.displayName,
  };
  await setDoc(doc(firestore, 'users', user.uid), newUserInfo);
  setUsername(newUserInfo.username);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 07:45:03