React-Redux集成chartjs-plugin-streaming折线图无法显示后续数据
问题原因
- 随机数生成逻辑仅执行1次:你将
generateRngNum的dispatch放在了仅依赖dispatch(引用永久不变)的useEffect中,只会在组件首次挂载时触发一次,后续图表每5秒刷新时不会生成新随机数,Redux中永远只存第一个生成的值。 - 图表数据集被反复重置:
data配置对象直接写在组件函数体内,每次组件因Redux状态更新重渲染时,三个数据集的data数组都会被重新初始化为空,之前推入的所有数据点直接丢失。 - 闭包陷阱:
onRefresh回调永久捕获组件第一次渲染时拿到的coTwoData值,后续Redux更新的新数据无法被回调读取,就算生成新值也拿不到。 - 逻辑脱节:
chartjs-plugin-streaming本身会按配置的refresh间隔定时触发onRefresh,你没有把新数据生成逻辑绑定到这个回调上,无法和图表刷新同步。
修复方案
- 移除组件首次加载时触发dispatch的
useEffect,把随机数生成逻辑移到onRefresh回调内,保证每次图表刷新都生成新值。 - 用
useMemo持久化图表data配置对象,避免重渲染时重置数据集数组。 - 用
useRef存储最新的Redux数据,解决onRefresh的闭包陷阱,保证回调能拿到最新生成的值。
修改后主组件代码
import { coTwoActions } from "../../store/redux"; import { useDispatch, useSelector } from "react-redux"; import React, { useEffect, useMemo, useRef } from "react"; import "chart.js/auto"; import "./chartLiveData.css"; import plugins from "../Settings/plugins"; import { Line } from "react-chartjs-2"; import { Chart } from "chart.js"; import ChartStreaming from "chartjs-plugin-streaming"; import "chartjs-adapter-luxon"; import Zoom from "chartjs-plugin-zoom"; Chart.register(Zoom); Chart.register(ChartStreaming); const ChartLiveDataReduxV3 = () => { const dispatch = useDispatch(); // 持久化图表配置,避免重渲染重置数据集 const data = useMemo(() => ({ datasets: [ { label: "400-1000 ppm", data: [], fill: false, backgroundColor: "rgba(0, 255, 0, 0.5)", showLine: false, pointStyle: "circle", pointRadius: 5, pointHoverRadius: 10, }, { label: "1001-2000 ppm", data: [], fill: false, backgroundColor: "rgba(255, 255, 0, 0.5)", showLine: false, pointStyle: "circle", pointRadius: 5, pointHoverRadius: 10, }, { label: "2001 + ppm", data: [], fill: false, backgroundColor: "rgba(255, 0, 0, 0.5)", showLine: false, pointStyle: "circle", pointRadius: 5, pointHoverRadius: 10, }, ], }), []); const coTwoData = useSelector((state) => state.coTwoData); // 用ref存储最新数据,解决闭包问题 const coTwoDataRef = useRef(coTwoData); useEffect(() => { coTwoDataRef.current = coTwoData; }, [coTwoData]); const onRefresh = () => { // 每次刷新先生成新随机数 dispatch(coTwoActions.generateRngNum()); const latestData = coTwoDataRef.current; const latestValue = latestData[latestData.length - 1]; if (!latestValue) return; const { x, y } = latestValue; // 按数值区间推入对应数据集 if (y <= 1000) { data.datasets[0].data.push({x, y}); } else if (y <= 2000) { data.datasets[1].data.push({x, y}); } else { data.datasets[2].data.push({x, y}); } }; const options = { scales: { x: { title: { display: true, text: "Real-Time", }, type: "realtime", realtime: { duration: 60000, // 图表展示最近60秒数据 refresh: 5000, // 5秒刷新一次 delay: 1000, pause: false, onRefresh: onRefresh, }, }, y: { title: { display: true, text: "ppm value CO2", }, }, }, }; return ( <div> <h1 className="centered"> Carbon Dioxide (CO<sub className="sub">2</sub>) </h1> <div className="container container-prop" style={{ width: "1000px", margin: "0 auto" }} > <Line data={data} plugins={plugins} options={options} /> </div> </div> ); }; export default ChartLiveDataReduxV3;
你提供的Redux模块代码逻辑正确,基于Immer的状态更新写法符合Redux Toolkit规范,不需要修改。
内容的提问来源于stack exchange,提问作者Antonis Papadakis
相关产品推荐
相关产品推荐

