Firebase Realtime DB列表展示时触发useState无限循环问题求助
问题分析与解决
你的无限循环问题根源在于组件渲染逻辑的错误:
- 组件每次渲染时,都会直接执行
load()和setContent(),而setContent会触发组件重新渲染,重新渲染又会重复执行这些代码,形成无限循环。 - 普通变量
array在组件每次渲染时都会被重新初始化,而且Firebase的onValue是异步回调,当数据返回时,组件可能已经完成渲染,此时修改array无法触发视图更新,同时还会导致数据累积问题。
修复方案
核心修改点
- 用
useState存储从数据库获取的分数数组,而非直接存储JSX - 用
useEffect包裹数据加载逻辑,确保只在组件挂载时执行一次,避免重复触发 - 在
onValue回调中正确更新状态,每次获取新数据时重置数组,避免重复添加数据 - 直接在渲染阶段映射数组生成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
相关产品推荐
相关产品推荐

