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

React中如何从Firebase Realtime Database正确获取数据?

问题根源

  1. 高频重复请求:使用Firebase的on()方法注册实时监听器后,没有在组件卸载时解绑,每次组件重新挂载都会新增一个监听器,多个监听器同时触发就会产生重复请求。
  2. 刷新页面空白:setFetchedData的调用位置在监听器回调之外,Firebase的on()监听是异步操作,注册完监听器立刻执行set操作时,还没拿到数据库返回的数据,此时写入state的是空值,页面自然显示空白;切换组件再切回时,之前的监听器已经拿到了数据,state有值所以显示正常。
  3. 数据结构不匹配: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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 13:45:01