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

React Redux二次登录后头像不显示问题求助

React应用二次登录后头像无法显示问题修复

问题现象

注册完成自动登录时,Banner组件的Avatar能正常展示头像;但退出账号重新登录后,头像消失,控制台打印显示user.photoUrl为undefined。

核心原因

  1. 注册时未同步头像地址到Firebase用户Profile:注册流程仅更新了displayName,未将用户输入的头像地址profpic保存到Firebase用户Profile中,导致二次登录时从Firebase获取的用户信息里photoURL字段为空。
  2. 字段映射需统一:登录时从Firebase取的是photoURL(大写URL),但Redux中使用的是photoUrl(小写Url),虽JS大小写敏感,但核心问题仍是Firebase未持久化头像地址。

修复方案

1. 修改注册逻辑,同步头像到Firebase

在register方法中,更新用户Profile时同时设置photoURL,确保Firebase持久化头像地址:

const register = () => {
  if (!name) {
    return alert("Please enter your name!");
  }
  auth
    .createUserWithEmailAndPassword(email, password)
    .then((userAuth) => {
      // 同时更新displayName和photoURL到Firebase用户Profile
      userAuth.user.updateProfile({
        displayName: name,
        photoURL: profpic
      }).then(() => {
        dispatch(
          login({
            email: userAuth.user.email,
            uid: userAuth.user.uid,
            displayName: name,
            photoUrl: profpic,
          })
        );
      });
    })
    .catch((error) => alert(error));
};

2. 统一登录逻辑的字段映射

确保登录时Firebase返回的photoURL正确映射到Redux的photoUrl字段:

const loginToApp = (e) => {
  e.preventDefault();

  auth
    .signInWithEmailAndPassword(email, password)
    .then((userAuth) => {
      dispatch(
        login({
          email: userAuth.user.email,
          uid: userAuth.user.uid,
          displayName: userAuth.user.displayName,
          photoUrl: userAuth.user.photoURL, // 映射Firebase字段到Redux字段
        })
      );
    })
    .catch((error) => alert(error));
};

3. 可选:Banner组件添加空值兜底

避免头像地址为空时出现异常,给Avatar添加默认内容:

// 替换Banner组件中的Avatar代码
<Avatar src={user?.photoUrl || ""}>{user?.displayName?.charAt(0)}</Avatar>

原代码参考

Banner组件原代码

import React from "react";
import "./Banner.css";
import { logout } from "./features/userSlice";
import { auth } from "./firebase";
import { useDispatch, useSelector } from "react-redux";
import { selectUser } from "./features/userSlice";
import logo from "./images/logo.png";
import SearchIcon from "@mui/icons-material/Search";
import { Avatar } from "@mui/material";

function Banner() {
  const user = useSelector(selectUser);
  console.log(user);
  const dispatch = useDispatch();
  const logoutOfApp = () => {
    dispatch(logout());
    auth.signOut();
  };

  console.log({ photoUrl: user?.photoUrl });
  return (
    <div className="banner">
      <div class="banner_container">
        <div className="banner_title">
          <h1>Hobby Hunter</h1>
          <img src={logo} alt="Hobby Hunter logo" />
        </div>
        {user ? (
          <div className="banner_right">
            <div className="header_search">
              <SearchIcon />
              <input placeholder="" type="text" />
            </div>
            <h2 className="user">Welcome {user.displayName}!</h2>
            <Avatar src={user.photoUrl}></Avatar>
            <button onClick={logoutOfApp}>Logout</button>
          </div>
        ) : null}
      </div>
    </div>
  );
}

export default Banner;

Login组件原代码

import React, { useState } from "react";
import { auth } from "./firebase";
import "./Login.css";
import { useDispatch } from "react-redux";
import { login } from "./features/userSlice";
import hpic from "./images/hpic.png";

function Login() {
  const [name, setName] = useState("");
  const [profpic, setProfpic] = useState("");
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const dispatch = useDispatch();

  const loginToApp = (e) => {
    e.preventDefault();

    auth
      .signInWithEmailAndPassword(email, password)
      .then((userAuth) => {
        dispatch(
          login({
            email: userAuth.user.email,
            uid: userAuth.user.uid,
            displayName: userAuth.user.displayName,
            photoUrl: userAuth.user.photoURL,
          })
        );
      })
      .catch((error) => alert(error));
  };
  const register = () => {
    if (!name) {
      return alert("Please enter your name!");
    }
    auth
      .createUserWithEmailAndPassword(
        email,
        password
      )
      .then((userAuth) => {
        userAuth.user.updateProfile({ displayName: name }).then(() => {
          dispatch(
            login({
              email: userAuth.user.email,
              uid: userAuth.user.uid,
              displayName: name,
              photoUrl: profpic,
            })
          );
        });
      })
      .catch((error) => alert(error));
  };
  return (
    <div className="loginScreen">
      <form>
        <input
          value={name}
          onChange={(e) => setName(e.target.value)}
          placeholder="Full name (required if registering)"
          type="text"
        />
        <input
          value={profpic}
          onChange={(e) => setProfpic(e.target.value)}
          placeholder="Profile Pic (optional)"
          type="text"
        />
        <input
          value={email}
          onChange={(e) => setEmail(e.target.value)}
          placeholder="Email"
          type="email"
        />

        <input
          value={password}
          onChange={(e) => setPassword(e.target.value)}
          placeholder="Password"
          type="password"
        />

        <button type="submit" onClick={loginToApp}>
          Sign In
        </button>

        <p>
          Not a member?
          <span className="login_register" onClick={register}>
            Register Now
          </span>
        </p>
      </form>
      <img src={hpic} alt="login pic" />
    </div>
  );
}

export default Login;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 04:45:03