I'm working on a React component that displays a line chart using react-chartjs-2. The chart should update whenever new data (apiData) is received from an API. The issue I'm facing is that if the new apiData value is the same as the previous one, the chart does not update or re-render.
Here’s the relevant part of my component:
import React, { useState, useContext, useEffect } from 'react';
import { Line } from 'react-chartjs-2';
import { DataContext } from '../../context/DataContext';
import 'chart.js/auto';
import styled from 'styled-components';
const MAX_DATA_POINTS = 100;
const Container = styled.div`
width: 99%;
height: 100%;
`;
const Graph = ({ apiData, graphLabel }) => {
const { streaming, clearFlag, setClearFlag } = useContext(DataContext);
const [graphData, setGraphData] = useState(() => {
const storedData = sessionStorage.getItem('graphData');
return storedData ? JSON.parse(storedData) : [];
});
const [key, setKey] = useState(0); // new state to track re-renders
useEffect(() => {
if (streaming) {
setGraphData(prevData => {
const newData = [
...prevData,
{ time: new Date().toLocaleTimeString(), data: apiData }
];
// Limit the number of data points to preserve interval
if(newData.length > MAX_DATA_POINTS){
newData.shift();
}
sessionStorage.setItem('graphData', JSON.stringify(newData));
setKey(prevKey => prevKey + 1); // trigger re-render
return [...newData]; // return new array to trigger re-render
});
}
}, [apiData, streaming]);
const dataPoints = {
labels: graphData.map(d => d.time),
datasets: [
{
label: graphLabel,
data: graphData.map(d => d.data),
fill: false,
backgroundColor: '#F3F4F6',
borderColor: '#0077C8',
},
],
};
useEffect(() => {
if (clearFlag) {
setGraphData([]);
sessionStorage.removeItem('graphData');
setClearFlag(false);
}
}, [clearFlag])
const options = {
scales: {
y: {
beginAtZero: true,
max: 1000,
},
},
maintainAspectRatio: false,
animation: {
duration: 0,
},
plugins: {
legend: {
labels: {
font: {
size: 18,
weight: 'bold',
},
color: 'black'
}
}
}
};
return (
<Container>
<Line data={dataPoints} options={options} />
</Container>
);
};
export default Graph;
I just add a timestamp to compare and trigger a re-render.
useEffect(() => {
if (streaming && apiData !== null) {
setGraphData(prevData => {
const newData = [
...prevData,
{ time: new Date().toLocaleTimeString(), data: apiData }
];
// Limit the number of data points to preserve interval
if(newData.length > MAX_DATA_POINTS){
newData.shift();
}
sessionStorage.setItem('graphData', JSON.stringify(newData));
return [...newData]; // return new array to trigger re-render
});
}
}, [apiData, timestamp, streaming]);
Thanks stackoverflow for nothing again.