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

React三元条件渲染中无法访问auth.currentUser的原因

问题说明
  • 开发目标:用户登录状态下展示Sign Out按钮,未登录状态下展示Sign In按钮。
  • 现象:初始代码中在登录回调里可以正常获取auth.currentUser,将按钮渲染改为三元表达式判断后,auth.currentUser取值变为null。

初始可正常打印用户信息的代码如下:

const JoinCard = () => {
  const auth = getAuth(app);
  const [user] = useAuthState(auth);
  const usersRef = collection(db, "users");

  const signInWithGoogle = async (e) => {
    e.preventDefault();
    const provider = new GoogleAuthProvider();

    signInWithPopup(auth, provider)
      .then((result) => {
        console.log(result);
        console.log(auth.currentUser);
      })
      .catch((error) => {
        console.log(error);
      });

    const { uid, photoURL, displayName } = auth.currentUser;
    await addDoc(usersRef, {
      uid: uid,
      photoURL: photoURL,
      displayName: displayName,
    });
  };

  return (
    <div className="w-[85vw] h-[30vh] m-2 rounded-2xl drop-shadow-xl flex justify-center items-center p-2 bg-white/75">
      <button className="sign-in" onClick={signInWithGoogle}>
        Sign in with Google
      </button>
    </div>
  );
};

function SignOut() {
  return (
    auth.currentUser && (
      <button className="sign-out" onClick={() => auth.signOut()}>
        Sign Out
      </button>
    )
  );
}

export default JoinCard;

调整为三元渲染后出现问题的代码片段:

return (
    <div className="w-[85vw] h-[30vh] m-2 rounded-2xl drop-shadow-xl flex justify-center items-center p-2 bg-white/75">
      {user ? (
        <SignOut />
      ) : (
        <button className="sign-in" onClick={signInWithGoogle}>
          Sign in with Google
        </button>
      )}
    </div>
  );
};
  );
触发原因
  1. 组件作用域访问错误
    你之前的代码里虽然定义了SignOut组件,但初始返回的JSX中根本没有渲染这个组件,组件内部的代码从未执行,所以没有暴露问题。等你加上三元判断,登录后满足渲染条件挂载SignOut时,才会执行组件内部逻辑:SignOut是定义在JoinCard外层的独立函数,而auth是JoinCard内部用const声明的局部变量,外层函数无法访问到这个局部变量,此时SignOut里的auth要么是未定义,要么是全局作用域下初始值为null的auth实例,自然拿不到currentUser。
    另外你之前能正常打印auth.currentUser,是因为打印逻辑写在JoinCard组件内部的登录回调里,本身就在auth变量的作用域范围内,和SignOut组件的访问逻辑无关。

  2. 异步逻辑时序错误(隐藏bug)
    你的signInWithGoogle方法里,signInWithPopup是异步Promise,你在then回调外同步执行const { uid, photoURL, displayName } = auth.currentUser时,弹窗登录流程还没走完,此时auth.currentUser本身就是null,就算解决了作用域问题,这里也会抛出解构错误。

  3. 语法错误
    你贴出的修改后返回代码末尾多写了一组);,本身就存在语法闭合问题。

修复方案
  • 把SignOut组件移到JoinCard组件内部定义,让它可以直接访问同作用域下的auth实例;也可以给SignOut新增props传入auth和user状态,不要让子组件依赖父组件未传值的局部变量。
  • 把写入Firestore的用户数据操作移到signInWithPopup的异步回调里,或者加await等待登录流程完成后再读取currentUser取值,不要同步读取异步状态。
  • 删除多余的语法闭合符号。

修复后的参考代码:

const JoinCard = () => {
  const auth = getAuth(app);
  const [user] = useAuthState(auth);
  const usersRef = collection(db, "users");

  const signInWithGoogle = async (e) => {
    e.preventDefault();
    const provider = new GoogleAuthProvider();
    try {
      // 等待登录流程完成再执行后续操作
      const result = await signInWithPopup(auth, provider);
      console.log(result);
      const { uid, photoURL, displayName } = auth.currentUser;
      await addDoc(usersRef, {
        uid: uid,
        photoURL: photoURL,
        displayName: displayName,
      });
    } catch (error) {
      console.log(error);
    }
  };

  // SignOut移到组件内部,可直接访问作用域内的auth和user状态
  const SignOut = () => {
    return (
      user && (
        <button className="sign-out" onClick={() => auth.signOut()}>
          Sign Out
        </button>
      )
    );
  };

  return (
    <div className="w-[85vw] h-[30vh] m-2 rounded-2xl drop-shadow-xl flex justify-center items-center p-2 bg-white/75">
      {user ? (
        <SignOut />
      ) : (
        <button className="sign-in" onClick={signInWithGoogle}>
          Sign in with Google
        </button>
      )}
    </div>
  );
};

export default JoinCard;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 16:54:21