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

页面刷新时useEffect异常及react-typed无限循环问题求助

问题分析
  • 刷新页面报错的核心原因:AuthContext 中的 user 在页面刷新后是异步初始化的,初始值为 undefined。此时 useEffect 依赖 user 执行时,直接访问 user.uid 会触发「读取undefined的属性」错误,导致组件渲染失败,进而引发 react-typed 内部的异常(控制台的 indexOf 报错是连锁反应)。
  • 移除 user 依赖后出现无限循环:因为 useEffect 没有依赖限制,每次组件渲染都会执行,而 setUserDetails 会更新状态触发重新渲染,形成循环。
正确的 useEffect 用法及修复方案
  1. 添加用户存在性判断:在 useEffect 内部先检查 user 是否存在,避免在未初始化时执行数据库操作。
  2. 保留 user 在依赖数组中:确保仅当 user 变化时才重新获取用户信息,避免不必要的重复请求和无限循环。
  3. 处理异步操作的取消(可选但推荐):添加组件卸载时的清理逻辑,防止组件卸载后异步请求仍在进行导致内存泄漏。
  4. 优化用户信息初始状态:避免渲染时 userDetails.displayName 为 undefined,可设置初始状态为 null 并添加加载状态或默认值。
修改后的完整代码
import React, { useState, useEffect } from "react";
import Typed from "react-typed";
import { UserAuth } from "../contexts/AuthContext";
import { db } from "../utils/firebase/firebase.utils";
import { doc, getDoc } from "firebase/firestore";

const Hero = () => {
  const [userDetails, setUserDetails] = useState(null);
  const { user } = UserAuth();

  useEffect(() => {
    // 当user未初始化时,直接返回,避免报错
    if (!user) return;

    let isMounted = true; // 标记组件是否挂载,用于清理异步操作

    const fetchData = async () => {
      try {
        const docRef = doc(db, "users", user.uid);
        const docSnap = await getDoc(docRef);
        // 仅当组件仍挂载时更新状态,防止内存泄漏
        if (isMounted && docSnap.exists()) {
          setUserDetails(docSnap.data());
        }
      } catch (error) {
        console.error("获取用户信息失败:", error);
      }
    };

    fetchData();

    // 组件卸载时的清理逻辑
    return () => {
      isMounted = false;
    };
  }, [user]); // 保留user作为依赖,确保仅当user变化时执行

  // 加载状态或默认显示
  if (!user || !userDetails) {
    return (
      <div className="text-white h-screen flex items-center justify-center">
        <p className="md:text-5xl sm:text-4xl text-xl font-bold">加载中...</p>
      </div>
    );
  }

  return (
    <div className="text-white">
      <div className="max-w-[800px] mt-[-96px] w-full h-screen mx-auto text-center flex flex-col justify-center">
        <div className="flex justify-center items-center">
          <Typed
            className="md:text-5xl sm:text-4xl text-xl font-bold md:pl-4 pl-2"
            strings={["Hello,", "Hola,"]}
            typeSpeed={120}
            backSpeed={140}
            loop
          />
          <p className="md:text-5xl sm:text-4xl text-xl font-bold py-4">
            {userDetails.displayName}!
          </p>
        </div>
      </div>
    </div>
  );
};

export default Hero;
关键说明
  • 用户存在性判断:if (!user) return 确保只有当 user 完成初始化后才执行数据库请求,从根源避免 user.uid 的访问错误。
  • 组件挂载标记:isMounted 变量防止组件卸载后异步请求完成仍更新状态,避免内存泄漏和控制台警告。
  • 加载状态处理:通过 if (!user || !userDetails) 显示加载提示,提升用户体验,同时避免渲染未完成的用户信息。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 19:30:55