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

React Native中useEffect内Firebase实时数据库查询循环问题求助

问题根因

你当前代码的核心问题有3个:

  • useEffect依赖数组错误加入了date、time、Temputure三个状态,只要这三个状态更新就会重新触发useEffect执行,形成无限循环
  • Firebase的on("value")是异步回调,你在绑定监听后同步执行状态更新时,回调还没有返回数据,此时写入状态的数组是空值
  • 没有做加载判断,空数据传入图表组件就会触发异常

修复方案

  1. 调整useEffect依赖为空数组,仅在组件首次挂载时初始化监听
  2. 新增加载状态,数据未完全拉取完成时显示加载提示,不渲染图表
  3. 每次异步回调拿到数据后再更新状态,同时校验数据完整性,全部拉取完成后关闭加载状态
  4. 新增监听清理逻辑,组件卸载时移除Firebase监听避免内存泄漏
  5. 补充Firebase的导入和初始化逻辑(你原代码遗漏了该部分)

修复后代码

import * as React from "react";
import { useState, useEffect } from "react";
import { StyleSheet, Text, View, Dimensions, ActivityIndicator } from "react-native";
import { LineChart } from "react-native-chart-kit";
// 补充Firebase导入,使用前请先完成Firebase初始化配置
import firebase from 'firebase/app';
import 'firebase/database';

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: "center",
    justifyContent: "center",
  },
  title: {
    fontSize: 20,
    fontWeight: "bold",
  },
  Temputure: {
    fontSize: 10,
    fontWeight: "bold",
  },
  separator: {
    marginVertical: 30,
    height: 1,
    width: "80%",
  },
});

export default function FireBaseTest() {
  const [Temputure, setTemputure] = useState([]);
  const [date, setDate] = useState();
  const [time, setTime] = useState([]);
  const [isLoading, setIsLoading] = useState(true);
  const graphTimeLengh = 12;
  // 数据总长度 = 从-1到graphTimeLengh-1,共graphTimeLengh+1个
  const DATA_TOTAL_COUNT = graphTimeLengh + 1;

  useEffect(() => {
    const db = firebase.database();
    const tempListeners = [];
    const timeListeners = [];
    let dateListener = null;

    // 拉取温度数据
    const temparray = new Array(DATA_TOTAL_COUNT).fill(null);
    for (let i = -1; i < graphTimeLengh; i++) {
      const ref = db.ref(`0/20-08-2021 ${i}/0/Temp`);
      const listener = ref.on("value", (snapshot) => {
        const response = snapshot.val();
        temparray[i + 1] = response;
        setTemputure([...temparray]);
        // 校验数据是否全部加载完成
        checkDataComplete();
      });
      tempListeners.push({ ref, listener });
    }

    // 拉取日期数据
    const dateRef = db.ref("0/20-08-2021 0/0/Date");
    dateListener = dateRef.on("value", (snapshot) => {
      const response = snapshot.val();
      setDate(response);
      checkDataComplete();
    });

    // 拉取时间数据
    const timearray = new Array(DATA_TOTAL_COUNT).fill(null);
    for (let i = -1; i < graphTimeLengh; i++) {
      const ref = db.ref(`0/20-08-2021 ${i}/0/Time`);
      const listener = ref.on("value", (snapshot) => {
        const response = snapshot.val();
        timearray[i + 1] = response;
        setTime([...timearray]);
        checkDataComplete();
      });
      timeListeners.push({ ref, listener });
    }

    // 校验所有数据是否加载完成
    const checkDataComplete = () => {
      const tempComplete = temparray.every(val => val !== null);
      const timeComplete = timearray.every(val => val !== null);
      if (tempComplete && timeComplete && date) {
        setIsLoading(false);
      }
    };

    // 组件卸载时清理所有监听
    return () => {
      tempListeners.forEach(({ ref, listener }) => ref.off("value", listener));
      timeListeners.forEach(({ ref, listener }) => ref.off("value", listener));
      dateRef.off("value", dateListener);
    };
  }, []); // 依赖为空,仅首次挂载执行

  const linedata = {
    labels: time,
    datasets: [
      {
        data: Temputure,
        strokeWidth: 5,
      },
    ],
  };

  return (
    <View style={styles.container}>
      <Text style={styles.title}>FireBaseTest</Text>
      <Text>{date || '加载中...'}</Text>
      {isLoading ? (
        <ActivityIndicator size="large" color="#ff0000" style={{ marginTop: 50 }} />
      ) : (
        <LineChart
          data={linedata}
          width={Dimensions.get("window").width}
          height={220}
          yAxisSuffix="°C"
          yAxisInterval={1}
          fromZero={true}
          chartConfig={{
            backgroundColor: "#1cc910",
            backgroundGradientFrom: "#eff3ff",
            backgroundGradientTo: "#efefef",
            decimalPlaces: 1,
            color: (opacity = 1) => `rgba(255, 0, 0, ${opacity})`,
            style: {
              borderRadius: 16,
            },
          }}
        />
      )}
    </View>
  );
}

后续提问建议

  • 错误信息优先贴文本内容而非截图,方便快速定位匹配问题
  • 可以补充你已经尝试过的方案、查阅过的资料,避免重复沟通
  • 贴代码时确保没有遗漏关键逻辑(比如导入、初始化部分)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 19:09:00