3

I am receiving data from an API and I want to take that data and have it populate my chart. I can see where the API data is being called and is being passed into setState but I cannot seem to correctly take this data and pass it to my chart.

I have tried using the destroy() and update() methods for Chart.js to no avail. I'm sure it is just a matter of me not using them correctly within my app. The code below does not include those methods since I wasn't sure where to use them. I have also tried pushing the API data into the data array for the chart with no luck.

componentDidMount() {
// create chart 
          new Chart(myChartRef, {
      type: "line",
      data: {
        labels: ["Jan", "Feb", "March"],
        datasets: [
          {
            data: this.state.chartData,
            backgroundColor: gradient,
            pointBackgroundColor: "#fff",
            pointBorderColor: gradient,
            pointRadius: "5",
            hoverBackgroundColor: "#75C6FF",
            hoverBorderColor: gradient
          }
        ]
      },
      options: {
        responsive: true,
        legend: {
          display: false
        },
        scales: {
          xAxes: [
            {
              gridLines: {
                color: "#535356"
              },
              ticks: {
                fontColor: "#87889C"
              }
            }
          ],
          yAxes: [
            {
              gridLines: {
                color: "#535356"
              },
              ticks: {
                fontColor: "#87889C"
              }
            }
          ]
        }
      }
    });
/* fetch API data and use it to set app state (setState) */
    const getChartData = () => {
      fetch(
        "https://min-api.cryptocompare.com/data/pricemulti?fsyms=BTC,ETH&tsyms=USD"
      )
        .then(response => {
          return response.json();
        })
        .then(myJson => {
          const bitcoinPrice = myJson.BTC.USD;
          this.setState({ chartData: bitcoinPrice });
          console.log(JSON.stringify(myJson));
        });
    };

    getChartData();
}

In the code I create a new chart once the component is mounted. Then I call the API and receive the data which I want to display on my chart. I can see in the React dev tools that the state is being set in my app but the chart does not update. I assume I need to do something like map the API data into the data array in the chart but I'm not sure how to do this properly and I have had no luck with the other solutions suggested on SO or anywhere else online.

This is my first React app so I'm not sure if I'm doing something wrong in React or in Chart.js?

DRD
  • 53
  • 1
  • 8

2 Answers2

1

From my experience, you can separate chart component and chart container. Make fetching in chart container and pass the fetched data as props to your chart component for better organization of code.

Also you need to check if props are changed with componentWillReceiveProps lifecycle method inside chart component and update the chart accordingly

  1. Create a component called ChartContainer.js and pass chartData to ChartComponent as props
import React, { Component } from 'react';
import ChartComponent from './ChartComponent'

export class ChartContainer extends Component {

  constructor(props) {
    super(props);
    this.state = {
      chartData: []
    }

  componentDidMount() {
    fetch(
        "https://min-api.cryptocompare.com/data/pricemulti?fsyms=BTC,ETH&tsyms=USD"
      )
        .then(response => {
          return response.json();
        })
        .then(myJson => {
          const bitcoinPrice = myJson.BTC.USD;
          this.setState({ chartData: bitcoinPrice });
          console.log(JSON.stringify(myJson));
        });
  }

  render() {
    const { chartData } = this.state;
    return (
        <ChartComponent chartData={chartData}/ >
    );
  }

}
  1. Create a component called ChartComponent and get chartData as props. Also make a state called chart and set the chart to the state and update the chart with componentWillReceiveProps lifecycle to update the chart.
import React, { Component } from 'react';

export class ChartComponent extends Component {

  constructor(props){
    super(props)
    this.state = { chart : null }
  }

  chart = React.createRef();

  componentDidMount(){
    // pass chartData to Chart below as this.props.chartData
    let theChart = new Chart(...)
    // set chart to state
    this.setState({ chart: theChart })
  }

  componentWillReceiveProps(nextProps, nextContext) {
    // update chart according to prop change
      this.state.chart.data.datasets.forEach((dataset) => {
        dataset.data.push(nextProps.chartData);
      });
      this.state.chart.update();
  }

  render(){
    return (
        <canvas id="myChart" ref={this.chart} />
    );
  }

};
onuriltan
  • 3,730
  • 4
  • 25
  • 37
  • Ok so I separated some of the code into 2 files like you suggested. While it does make things a little easier to read and understand I still can't get the chart to update. Am I supposed to use the map() method to iterate over the API data and pass that into the chartData array? I have seen this done but I am unsure how to implement it properly. – DRD Aug 06 '19 at 18:43
  • Every time props changes the component should re-render with new props, it should re-render with state change anyway but I used like that way in the past. However if it did not solve the problem, then you I guess can **call chart.update(); inside ChartComponent's componentDidMount method** – onuriltan Aug 06 '19 at 18:46
  • Hmmmm when I had tried that originally I got an error saying "chart.update is not a function" At first I thought that I had to use this.chart.update() instead of just chart.update() but I get the same error either way. – DRD Aug 06 '19 at 18:58
  • Actually you can hold the new Chart() inside a state variable referencing to it, then you can call this.myChartVar.update() ? – onuriltan Aug 06 '19 at 19:00
  • Can you look at [here my project](https://gitlab.com/TwitterAnalyzer/TwitterAnalyzerUI/blob/master/src/modules/board/charts/location_chart.jsx) I was updating chart.js like in this code. Also look at the related docs [here](https://www.chartjs.org/docs/latest/developers/updates.html) – onuriltan Aug 06 '19 at 19:03
  • That didn't seem to work either :/ I saw in your project you are using react-chartjs-2. I'm not using the Chart.js React wrapper because I ran into other issues with that so I stuck to using just Chart.js. I'm not sure if it helps but here is the Git repo for this project https://github.com/DRD161/crypto-graph. At least this way you can see all of my code and how everything fits together (or in some cases doesn't fit together) – DRD Aug 06 '19 at 19:45
  • Ok I will look at the repo – onuriltan Aug 06 '19 at 19:50
  • 1
    YES! thanks a bunch that's exactly what I needed. I knew there was some way I could pass the API response to the chart but I couldn't figure it out. Marking this as the answer :) – DRD Aug 06 '19 at 21:16
0

When props changed, ChartComponent is not refreshed. To make it work use redraw={true}

<ChartComponent type={chartType} {...someConfig} redraw={true}/>