0
votes

I'm building a dynamic chart using chart.js.

Within componentDidMount, I'm calling getNewData() every second with setInterval.

This updates the data within my dataset, for some reason the chart won't update / re-render when state is updated.

How can I get the chart to update it's points when new data is added?

Component code:

import React, {Component} from 'react';
import { Line } from 'react-chartjs-2';
import 'chartjs-plugin-lineheight-annotation';

import './styles.scss';

export default class SmallCard extends Component {

    constructor(props) {
        super(props);

        this.state = {
            data: {
                labels: ["1", "2", "3", "4", "5"],
                datasets: [
                    {
                        label: "Videos Made",
                        backgroundColor: "rgba(255, 0, 255, 0.75)",
                        data: [4, 5, 1, 10, 32, 2, 12]
                     },
                    {
                        label: "Subscriptions",
                        backgroundColor: "rgba(0, 255, 0, 0.75)",
                        data: [14, 15, 21, 0, 12, 24, 32]
                    }
                ]
            }
        }
    }

    componentDidMount() {
        this.interval = setInterval(() => this.getNewData(), 1000);
    }

    componentWillUnmount() {
      clearInterval(this.interval);
    }

    getNewData() {
        const min = 1;
        const max = 10;
        const rand = min + Math.floor(Math.random() * (max - min));
        this.setState({
            data: {
                datasets: this.state.data.datasets.map((item, index) => ({
                    ...item,
                    data: [...this.state.data.datasets[index].data, rand]
                }))
            }
        });
    }


    setGradientColour = (canvas, colour) => {
        const ctx = canvas.getContext('2d');
        //console.log("ctx", ctx)
        const gradient = ctx.createLinearGradient(0, 0, 0, 400);
        gradient.addColorStop(0, colour);
        gradient.addColorStop(0.95, "rgba(133, 255, 144, 0.85");
        return gradient;
    }

    getChartData = canvas => {
        const { data } = this.state;


        if(data.datasets) {
            let colors = ["rgba(255, 0, 255, 0.75)", "rgba(0, 255, 0, 0.75)"];
            data.datasets.forEach((set, i) => {
                set.backgroundColor = this.setGradientColour(canvas, colors[i]);
                set.borderColor = "white";
                set.borderWidth = 2;

            })
        }

        return data;
    }

    render() {
        const data  = this.state.data.datasets[1].data; 

        console.log("data", data)
        return (
            <div className="small-card-wrap">
                <Line 
                    options={{
                        responsive: true,
                        lineHeightAnnotation: {
                            always: false,
                            hover: true,
                            color: 'white',
                            noDash: true
                        }
                    }} 
                    data={this.getChartData} />
            </div>
        )
    }
}
1
What does the console log says? Is the new data in the console?PassionateDeveloper
Yes new data successfully within console.Filth

1 Answers

1
votes

getNewData is not bound to the class context, so the setState will fail. you can use an arrow function so it will inherit the enclosing one.

getNewData = () => {
        const min = 1;
        const max = 10;
        const rand = min + Math.floor(Math.random() * (max - min));
        this.setState({
            data: {
                datasets: this.state.data.datasets.map((item, index) => ({
                    ...item,
                    data: [...this.state.data.datasets[index].data, rand]
                }))
            }
        });
    }