React中如何从Firebase Realtime Database正确获取数据?
问题根源
- 高频重复请求:使用Firebase的
on()方法注册实时监听器后,没有在组件卸载时解绑,每次组件重新挂载都会新增一个监听器,多个监听器同时触发就会产生重复请求。 - 刷新页面空白:
setFetchedData的调用位置在监听器回调之外,Firebase的on()监听是异步操作,注册完监听器立刻执行set操作时,还没拿到数据库返回的数据,此时写入state的是空值,页面自然显示空白;切换组件再切回时,之前的监听器已经拿到了数据,state有值所以显示正常。 - 数据结构不匹配:state初始值是数组,但后续代码直接读取
fetchedData.TotalOrders这类对象属性,也会导致取值失败。
核心修正点
- 给useEffect添加清理函数,组件卸载时调用
db.off("value")解绑实时监听器,避免重复注册 - 将状态更新逻辑移动到监听器回调内部,确保拿到数据库返回数据后再更新state
- 调整state初始值为对象,匹配Firebase返回的
Orders节点数据结构 - 渲染时添加可选链做数据空值保护,避免初始加载时报错
修正后代码
import { useState, useEffect } from 'react'; import { Grid, Paper } from '@material-ui/core'; import Topbar from '../Utilities/Topbar'; import './Statistics.css'; import database from '../../firebase'; const Statistics = () => { // 初始值改为空对象,匹配Orders节点的数据结构 const [fetchedData, setFetchedData] = useState({}); useEffect(() => { const db = database.ref('Orders/'); // 监听回调内处理数据并更新state const handleDataChange = (snapshot) => { const data = snapshot.val(); setFetchedData(data || {}); } db.on("value", handleDataChange); // 清理函数,组件卸载时解绑监听器 return () => { db.off("value", handleDataChange); } }, []); return ( <Grid container> <Topbar /> <Grid container spacing={8}> <Grid item sm={12} md={7} > <h2 className="home_heading">Hi Name Surname</h2> <p className="home_text_alt">Welcome back</p> <p className="home_text">Statistics</p> <Grid container spacing={2}> <Grid item sm={4}> <div className="orders_1"> {/* 加可选链做空值保护 */} <h1>{fetchedData?.TotalOrders ?? '-'}</h1> <p>Total Orders</p> </div> </Grid> <Grid item sm={4}> <div className="orders_2"> <h1>40</h1> <p>Most Ordered</p> </div> </Grid> <Grid item sm={4}> <div className="orders_3"> <h1>{fetchedData?.Revenue ?? '-'}</h1> <p>Total Revenue</p> </div> </Grid> </Grid> <Paper elevation={3} className="graph"></Paper> </Grid> <Grid item sm={12} md={4}> <p className="home_text" style={{ marginBottom: "20px" }}>Popularity</p> <Grid container spacing={4}> <Grid item xs={10}> <Grid container className="summary_name"> <div className="summ_card_col"></div> <p>TYPE A - Petri Dish</p> </Grid> </Grid> <Grid item xs={1}> <div className="summary_count"> <p>4</p> </div> </Grid> </Grid> {/* 剩余重复的列表项保持原有逻辑,涉及动态数据的位置添加可选链即可 */} </Grid> </Grid> </Grid> ); } export default Statistics;
内容的提问来源于stack exchange,提问作者Akshat Uniyal
相关产品推荐
相关产品推荐

