React Native中useEffect内Firebase实时数据库查询循环问题求助
问题根因
你当前代码的核心问题有3个:
useEffect依赖数组错误加入了date、time、Temputure三个状态,只要这三个状态更新就会重新触发useEffect执行,形成无限循环- Firebase的
on("value")是异步回调,你在绑定监听后同步执行状态更新时,回调还没有返回数据,此时写入状态的数组是空值 - 没有做加载判断,空数据传入图表组件就会触发异常
修复方案
- 调整
useEffect依赖为空数组,仅在组件首次挂载时初始化监听 - 新增加载状态,数据未完全拉取完成时显示加载提示,不渲染图表
- 每次异步回调拿到数据后再更新状态,同时校验数据完整性,全部拉取完成后关闭加载状态
- 新增监听清理逻辑,组件卸载时移除Firebase监听避免内存泄漏
- 补充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
相关产品推荐
相关产品推荐

