如何用Highcharts、Firebase、ReactJS+TypeScript实现实时图表?
如何连接Firebase实现React+TypeScript+Highcharts实时图表获取新增数据
步骤1:配置Firebase依赖与初始化
- 安装Firebase SDK:
npm install firebase或yarn add firebase - 创建Firebase配置文件(比如
firebaseConfig.ts),填入你的项目信息:
import { initializeApp } from "firebase/app"; import { getFirestore } from "firebase/firestore"; const firebaseConfig = { apiKey: "YOUR_API_KEY", authDomain: "YOUR_AUTH_DOMAIN", projectId: "YOUR_PROJECT_ID", storageBucket: "YOUR_STORAGE_BUCKET", messagingSenderId: "YOUR_SENDER_ID", appId: "YOUR_APP_ID" }; const app = initializeApp(firebaseConfig); export const db = getFirestore(app);
步骤2:重构实时心率图表组件
移除原有的随机数据生成逻辑,改用Firestore的实时监听获取并更新图表数据:
修改后的GraphHeartRateMonitor组件:
import { useEffect, useRef } from 'react'; import { TooltipFormatterContextObject } from 'highcharts'; import { Chart, labelsStyle } from '../../../../shared/components/DataDisplay/Chart'; import { defaultTheme } from '../../../../shared/styles/themes'; import { formatDate } from '../../../../shared/utils/date'; import { db } from '../../../../firebaseConfig'; // 引入你的Firebase配置 import { collection, query, orderBy, limit, onSnapshot } from "firebase/firestore"; export const GraphHeartRateMonitor: React.FC = () => { const chartRef = useRef<HighchartsReact.RefObject>(null); const unsubscribeRef = useRef(() => {}); // 初始化图表配置 const options: Highcharts.Options = { chart: { borderWidth: 0, height: '176px', plotBackgroundColor: defaultTheme.palette.background.default, type: 'line', marginRight: 10, }, title: { text: '' }, xAxis: { type: 'datetime', tickPixelInterval: 300, labels: { enabled: false }, }, yAxis: { title: { text: '' }, gridLineColor: defaultTheme.palette.background.default, tickInterval: 10, labels: { enabled: false }, plotLines: [ { value: 120, color: defaultTheme.palette.red[300], width: 2, label: { text: '120', useHTML: true, verticalAlign: 'middle', align: 'left', style: { background: defaultTheme.palette.red[300], borderRadius: '24px', height: '18px', padding: '2px 12px', color: defaultTheme.palette.common.white, fontFamily: 'Roboto Mono', fontSize: '12px', fontWeight: '400', }, }, }, ], }, legend: { enabled: false }, exporting: { enabled: false }, series: [ { name: '心率数据', color: defaultTheme.palette.grey[900], data: [], // 初始空数据,后续从Firebase加载 }, ], tooltip: { useHTML: true, backgroundColor: defaultTheme.palette.background.paper, borderRadius: 4, shadow: { color: defaultTheme.palette.common.black }, padding: 12, style: labelsStyle(20, defaultTheme.palette.grey[300]), formatter() { const self: TooltipFormatterContextObject = this; return ` <span>时间:</span> <strong>${formatDate(new Date(self.x), 'HH:mm:ss')}</strong> </br> <span>心率:</span> <strong>${self.y} bpm</strong> `; }, }, }; useEffect(() => { // 构建Firestore查询:按时间排序,取最近20条数据(和原模拟数据数量一致) const heartRateCollection = collection(db, 'heartRates'); const q = query(heartRateCollection, orderBy('timestamp', 'desc'), limit(20)); // 实时监听数据变化 unsubscribeRef.current = onSnapshot(q, (snapshot) => { const chart = chartRef.current?.chart; if (!chart) return; const newData: [number, number][] = []; // 反转数据,保证时间从旧到新 snapshot.docs.reverse().forEach(doc => { const data = doc.data(); newData.push([data.timestamp, data.value]); }); // 初始化或更新图表数据 if (chart.series[0].data.length === 0) { chart.series[0].setData(newData); } else { // 只添加新增的数据 const lastTimestamp = chart.series[0].data[chart.series[0].data.length - 1]?.x || 0; const addedPoints = newData.filter(point => point[0] > lastTimestamp); addedPoints.forEach(point => { chart.series[0].addPoint(point, true, true); }); } }); // 组件卸载时取消监听,避免内存泄漏 return () => unsubscribeRef.current(); }, []); return <Chart ref={chartRef} options={options} />; };
步骤3:Firestore数据结构说明
你的Firestore集合(建议命名为heartRates)中的文档需要包含两个字段:
timestamp: 时间戳(number类型,对应JavaScript的Date.getTime())value: 心率数值(number类型)
测试用的新增数据代码示例:
import { db } from './firebaseConfig'; import { collection, addDoc } from "firebase/firestore"; // 模拟新增心率数据到Firestore const addHeartRateData = async (value: number) => { await addDoc(collection(db, 'heartRates'), { timestamp: new Date().getTime(), value: value }); };
关键说明
- 用
useRef保存图表实例和监听取消函数,避免组件重渲染时重复创建监听 onSnapshot会实时接收数据变化,包括初始加载和后续新增数据addPoint方法的第三个参数设为true,会自动移除最早的点,保持图表数据数量稳定(和原模拟逻辑一致)
内容的提问来源于stack exchange,提问作者Jecê Xavier
相关产品推荐
相关产品推荐

