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

Firebase实时数据库结合React时forEach循环无限执行问题

解决Firebase实时数据获取导致的无限循环问题

问题根源

  • Hook使用违规:你把useEffect嵌套在了onAuthStateChanged的回调内部,而且useEffect的第一个参数传了对象而非函数。React要求Hook必须在组件顶层调用,不能嵌套在任何回调、循环或条件判断里,错误写法会导致每次组件渲染都重复执行数据获取逻辑。
  • 状态更新触发循环:在rows.forEach里多次调用setMyArray,每次状态更新都会触发组件重新渲染,而错误的Hook逻辑又会再次发起数据库请求,进而再次更新状态,形成无限循环。
  • uid硬编码为空:代码里const uid = '';会导致数据库路径无效,无法正确获取目标数据。

修复方案

  1. 将onAuthStateChanged逻辑移到组件顶层的useEffect内部,遵循Hook使用规则;
  2. 一次性构建完整数组后再更新状态,避免多次调用setMyArray触发重复渲染;
  3. 从user对象中正确获取uid,保证数据库路径有效;
  4. 给useEffect添加依赖项,仅当路由参数变化时重新获取数据。

修复后的完整代码

import { useState, useEffect } from 'react';
import { useParams } from 'react-router-dom';
import { getDatabase, ref, get, child } from 'firebase/database';
import { getAuth, onAuthStateChanged } from 'firebase/auth';

function About() {
  const params = useParams();
  const [title, setTitle] = useState('');
  const [myArray, setMyArray] = useState([]);

  useEffect(() => {
    const auth = getAuth();
    // 订阅用户登录状态变化,返回取消订阅函数
    const unsubscribe = onAuthStateChanged(auth, (user) => {
      if (!user) {
        setMyArray([]);
        return;
      }
      
      const uid = user.uid;
      const db = getDatabase();
      const dbRef = ref(db);
      const targetPath = `users/${uid}/${params.hey}`;

      get(child(dbRef, targetPath))
        .then((snapshot) => {
          if (snapshot.exists()) {
            const snap = snapshot.val();
            const rows = snap['rows'];
            // 一次性生成目标数组,只更新一次状态
            const newArray = rows.map((_, index) => `${index}`);
            setMyArray(newArray);
          } else {
            console.log("目标数据不存在");
            setMyArray([]);
          }
        })
        .catch((error) => {
          console.error("获取数据失败:", error);
          setMyArray([]);
        });
    });

    // 组件卸载时取消登录状态监听,避免内存泄漏
    return unsubscribe;
  }, [params.hey]); // 依赖路由参数,参数变化时重新获取数据

  console.log('myArray', myArray);
  return (
    <>
      <main>
        <h2>{title}</h2>
        <div>
          {myArray.map((e, index) => (
            <div key={index}>{e}</div>
          ))}
        </div>
      </main>
    </>
  );
}

export default About;

关键修复说明

  • 把登录状态监听逻辑放在顶层useEffect中,符合React Hook的使用规则,同时通过返回unsubscribe函数清理监听,避免内存泄漏;
  • 使用rows.map一次性生成完整数组,仅调用一次setMyArray,减少不必要的组件渲染;
  • 从user对象中获取真实uid,确保数据库查询路径有效;
  • useEffect的依赖数组添加params.hey,保证路由参数变化时能重新获取对应数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 12:57:11