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

Firebase Realtime DB列表展示时触发useState无限循环问题求助

问题分析与解决

你的无限循环问题根源在于组件渲染逻辑的错误:

  • 组件每次渲染时,都会直接执行load()和setContent(),而setContent会触发组件重新渲染,重新渲染又会重复执行这些代码,形成无限循环。
  • 普通变量array在组件每次渲染时都会被重新初始化,而且Firebase的onValue是异步回调,当数据返回时,组件可能已经完成渲染,此时修改array无法触发视图更新,同时还会导致数据累积问题。

修复方案

核心修改点

  1. 用useState存储从数据库获取的分数数组,而非直接存储JSX
  2. 用useEffect包裹数据加载逻辑,确保只在组件挂载时执行一次,避免重复触发
  3. 在onValue回调中正确更新状态,每次获取新数据时重置数组,避免重复添加数据
  4. 直接在渲染阶段映射数组生成JSX,无需提前存入状态

修改后的完整代码

import React, { useState, useEffect } from 'react'
import '../../../node_modules/bootstrap/dist/css/bootstrap.css'
import 'bootstrap'
// Import the functions you need from the SDKs you need
import { initializeApp } from "https://www.gstatic.com/firebasejs/9.18.0/firebase-app.js";
import { getAnalytics } from "https://www.gstatic.com/firebasejs/9.18.0/firebase-analytics.js";
import { getAuth } from "https://www.gstatic.com/firebasejs/9.18.0/firebase-auth.js"
import { getDatabase, ref, onValue } from "https://www.gstatic.com/firebasejs/9.18.0/firebase-database.js";
//components
import RenderArray from '../RenderArray';

//firebase     
// Your web app's Firebase configuration
const firebaseConfig = {
  apiKey: "AIzaSyBgoMjqs2soEsMlcgb3AztqjoDQuD5Dly8",
  authDomain: "moneyapp-5f530.firebaseapp.com",
  projectId: "moneyapp-5f530",
  storageBucket: "moneyapp-5f530.appspot.com",
  messagingSenderId: "800356072567",
  appId: "1:800356072567:web:b32b2359111e2acc761a72"
};
const app = initializeApp(firebaseConfig);
const auth = getAuth();

const LoadHistory = () => {
  const [notes, setNotes] = useState([])

  useEffect(() => {
    const unsubscribeAuth = auth.onAuthStateChanged(user => {
      if (user) {
        const userId = user.uid;
        const db = getDatabase();
        const historyRef = ref(db, 'users/' + userId);
        
        // 监听数据库变化,返回取消监听的函数
        const unsubscribeDb = onValue(historyRef, (snapshot) => {
          const newNotes = [];
          snapshot.forEach((childSnapshot) => {
            const childData = childSnapshot.val();
            newNotes.push(childData.note);
          });
          setNotes(newNotes);
        });

        // 组件卸载时取消数据库监听
        return () => unsubscribeDb();
      }
    });

    // 组件卸载时取消Auth状态监听
    return () => unsubscribeAuth();
  }, []); // 空依赖数组,确保只在组件挂载时执行一次

  return (
    <div>
      {notes.map((note, index) => (
        <div key={index} className="user">{note}</div>
      ))}
    </div>
  )
}

export default LoadHistory

关键细节说明

  • useEffect的空依赖数组:确保数据加载逻辑只在组件第一次挂载时执行,不会因组件重新渲染重复触发,从根源解决无限循环。
  • 取消监听函数:在useEffect的返回值中添加取消Auth和数据库监听的逻辑,避免组件卸载后仍然监听数据变化导致内存泄漏。
  • 状态更新逻辑:每次数据库数据变化时,重新创建新的数组newNotes,再通过setNotes更新状态,确保视图能正确响应数据变化。
  • 渲染阶段生成JSX:直接在return中映射notes数组生成DOM元素,无需提前将JSX存入状态,符合React的状态管理最佳实践。

关于写入数据的补充优化

你的writeUserData函数可以简化,无需每次写入都监听Auth状态(建议在组件中提前获取当前用户,或确保调用该函数时用户已登录):

import { getDatabase, ref, push, set } from "https://www.gstatic.com/firebasejs/9.18.0/firebase-database.js";
import { getAuth } from "https://www.gstatic.com/firebasejs/9.18.0/firebase-auth.js"

const auth = getAuth();

function writeUserData(note) {
  const user = auth.currentUser;
  if (user) {
    const userId = user.uid;
    const db = getDatabase();
    const notenRef = ref(db, 'users/' + userId);
    const newNoteRef = push(notenRef);
    set(newNoteRef, { note });
  } else {
    console.log('Not logged in ');
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 02:32:48