'react-chartjs-2 does not show line until window is resized
I'm having this weird bug with my React app with the react-chartjs-2. Chart data does not show correctly until I resize window. Tested on Firefox and Chrome, same result. Data is there, but I don't know if the data is loaded after the render or something. Please, I am student and not an expert, so please explain in detail if you know the solution for my problem. Thank you!
import React, {Component} from 'react';
import {Line} from 'react-chartjs-2';
const options = {
title: {
display: true,
text: "Chart Title"
},
scales: {
yAxes: [
{
ticks: {
suggestedMin: 20,
suggestedMax: 50
}
}
]
}
};
const legend = {
display: true,
position: "bottom",
labels: {
fontColor: "#323130",
fontSize: 14
}
};
class SensorChart extends Component {
constructor(props) {
super(props);
this.chartReference = React.createRef()
this.state = {
data : {
labels: props.labels,
datasets: [
{
label: "Humidity",
borderColor: "rgb(9,0,192)",
data: props.humidity
},
{
label: "Temperature",
borderColor: "red",
data: props.temperature
}
]
}
}
}
componentDidMount() {
console.log(this.state.data.datasets[0].data)
console.log(this.state.data.datasets[1].data)
}
render() {
return (
<div>
<h5>Line Example</h5>
<Line ref={this.chartReference} data={this.state.data} legend={legend} options={options}/>
</div>
);
}
}
export default SensorChart;
import React from 'react';
import Icon from '@mdi/react'
import {mdiThermometer, mdiWaterPercent, mdiCalendarRange} from '@mdi/js';
import './SensorData.css';
import SensorChart from "./SensorChart";
function SensorData() {
const [humi, setHumi] = React.useState("");
const [temp, setTemp] = React.useState("");
const [date, setDate] = React.useState("");
const [labels] = React.useState([]);
const [humidity] = React.useState([]);
const [temperature] = React.useState([]);
function fetchData() {
fetch('https://myAPIurl/datalist/100')
.then(response => response.json())
.then(responseData => {
setDate(responseData[0].stringTime);
setHumi(responseData[0].humidity);
setTemp(responseData[0].temperature);
for (let i = 0; i < 100; i++) {
labels.push(responseData[i].stringTime)
humidity.push(responseData[i].humidity)
temperature.push(responseData[i].temperature)
}
})
}
React.useEffect(() => {
fetchData();
}, []);
return (
<div className="App">
<h1>Sensor data</h1>
<h3><Icon path={mdiWaterPercent}/> Humidity: {humi}%</h3>
<h3><Icon path={mdiThermometer}/>Temperature: {temp}°C</h3>
<h3><Icon path={mdiCalendarRange}/>Time: {date}</h3>
<div className="Chart">
<SensorChart labels={labels} humidity={humidity} temperature={temperature}/>
</div>
</div>
);
}
export default SensorData;
Console logs after site is loaded
console.log(this.state.data.datasets[0].data)
console.log(this.state.data.datasets[1].data)
_chartjs: {…}, push: ƒ, pop: ƒ, shift: ƒ, splice: ƒ, …]0: 371: 372: 353: 354: 355: 366: 387: 388: 409: 4110: 4711: 4312: 4013: 3714: 3615: 3516: 3717: 3618: 3619: 3620: 3621: 3622: 3623: 3624: 3625: 3626: 3627: 3628: 3629: 3630: 3631: 3632: 3633: 3634: 3635: 3736: 3737: 3738: 3739: 3840: 3841: 3842: 3843: 3844: 3845: 3846: 3947: 3948: 3949: 4050: 4151: 4152: 4153: 4154: 4255: 4356: 4357: 4458: 4459: 4360: 3961: 4062: 3963: 3864: 3765: 3666: 3667: 3768: 3769: 3770: 3771: 3672: 3673: 3574: 3575: 3676: 3577: 3678: 3679: 3580: 3681: 3782: 3783: 3784: 3885: 3886: 3887: 3888: 3789: 3890: 3891: 3792: 3793: 3794: 3795: 3796: 3797: 3798: 3799: 37length: 100_chartjs: {listeners: Array(1)}push: ƒ ()pop: ƒ ()shift: ƒ ()splice: ƒ ()unshift: ƒ ()__proto__: Array(0)
SensorChart.js:61 [_chartjs: {…}, push: ƒ, pop: ƒ, shift: ƒ, splice: ƒ, …]0: 24.31: 24.32: 24.33: 24.24: 24.15: 23.86: 22.87: 22.98: 23.59: 2410: 24.811: 24.812: 24.713: 24.514: 24.515: 24.516: 24.617: 24.518: 24.519: 24.520: 24.421: 24.422: 24.423: 24.424: 24.525: 24.426: 24.427: 24.428: 24.429: 24.430: 24.431: 24.432: 24.433: 24.434: 24.335: 24.436: 24.437: 24.538: 24.539: 24.540: 24.541: 24.442: 24.543: 24.544: 24.545: 24.546: 24.547: 24.448: 24.349: 24.450: 24.451: 24.452: 24.453: 24.554: 24.555: 24.556: 24.557: 24.558: 24.559: 24.560: 24.561: 24.562: 24.563: 24.564: 24.565: 24.566: 24.567: 24.468: 24.469: 24.470: 24.471: 24.472: 24.373: 24.374: 24.375: 24.376: 24.377: 24.378: 24.379: 24.380: 24.381: 24.482: 24.483: 24.384: 24.385: 24.386: 24.387: 24.388: 24.389: 24.490: 24.291: 24.392: 24.293: 24.294: 24.295: 24.296: 24.197: 24.198: 24.299: 24.1length: 100_chartjs: {listeners: Array(1)}push: ƒ ()pop: ƒ ()shift: ƒ ()splice: ƒ ()unshift: ƒ ()__proto__: Array(0)
Solution 1:[1]
For everyone who is still ending up here, this seems to be an actively tracked issue at the moment since about 2017 on their GitHub Repo (#90). Although the issue is closed at the moment (2021-Apr-01), it is obviously still a problem for a lot of users as it has received comments on GitHub itself quite recently as well as here on Stack Overflow.
Previously listed solutions:
Redraw:
Apparently including the redraw prop on the React-ChartJS-2 component call is supposed to force a redraw of the data:
return (
<Line data={chartData} options={options} title="My Chart" ref={chartRef} redraw />
)
Sadly, this did nothing for me...
useEffect():
By tying the charts actual data into a useState() hook, it will trigger a component reload every time you change the data, which if you plan it right can also include initial data load.
const [chartData, setChartData] = useState(null);
// Data Fetch
useEffect(() => {
//...Async fetch my data from source and update state
});
// Attempt at triggering update whenever datasets change:
useEffect(() => {
if (chartData !== null) {
chartRef.current.chartInstance.update({
preservation: true,
});
}
}, [chartData]);
// Nested component to trigger rerender of only the graph for performance
const Graph = () => {
return (
<>
{chartData ? (
<Line data={chartData} options={options} title="My Chart" ref={chartRef} redraw />
) : null}
</>
);
};
return (
<Graph />
)
Sadly (again), this also did nothing...
Conclusion:
This appears to be a bug with how ChartJS was ported to React, meaning this appears to be an issue with the actual React-ChartJS-2 package.
TL;DR
Its a known issue on the React-ChartJS-2 GitHub (#90). Normal approaches do not work currently. Stay tuned there for updates.
Solution 2:[2]
After a few tinkering about I finally managed to get the Line graph to re-render when the data is received.
You may need to make use of both useState and useEffect, how I got around it is by updating the state to hold the datasets when data received has changed
const [data, setData] = React.useState<any>({ datasets: [{ data: [] }] });
And the useEffect with the data sets and labels as the dependencies
React.useEffect(() => {
setData({
labels: label,
datasets: [
{
data: datavals,
borderColor: "#59F5FF",
backgroundColor: "none",
pointBackgroundColor: "#59F5FF",
pointBorderWidth: 5,
pointHoverRadius: 10,
tension: 0.4
}
]
});
}, [label, datavals]);
then further down in the Line component
return <Line data={data} />;
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Graeme Ford |
| Solution 2 | Dharman |
