Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change series data dynamically in react-highcharts without re-render of the chart

I have created a line chart using react-highcharts. It has 3 series and different data for each of them. And I have a range-selector that changes the data of the series dynamically. The chart looks like this: crg It works all fine but the problem is whenever I change the risk value on the range-selector, the chart re-renders with new series' data. I don't want it to re-render every time. I want the series' data change with animation. Something like this: Live random data. And here is my related code:

class ContributionRiskGraph extends React.Component {
  constructor() {
    super();

    this.state = {
      riskValue: 8.161736
    };

    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(value) {
    this.setState({
      riskValue: value
    });
  }

  render() {
    const riskValue = this.state.riskValue / 100;
    const LBData = getGraphPlotData(riskValue, 'lowerBound');
    const EVData = getGraphPlotData(riskValue, 'expectedValue');
    const UBData = getGraphPlotData(riskValue, 'upperBound');

    const config = {
      chart: {
        animation: {
          duration: 1000
        }
      },
      title: {
        text: 'Contribution Risk Graph'
      },
      series: [
        {
          name: 'Lower Bound',
          data: LBData,
          type: 'spline',
          tooltip: {
            valueDecimals: 2
          }
        },
        {
          name: 'Expected Value',
          data: EVData,
          type: 'spline',
          tooltip: {
            valueDecimals: 2
          }
        },
        {
          name: 'Upper Bound',
          data: UBData,
          type: 'spline',
          tooltip: {
            valueDecimals: 2
          }
        }
      ],
      yAxis: {
        gridLineWidth: 0,
        opposite: true
      },
      xAxis: {
        gridLineWidth: 2,
        labels: {
          formatter: function() {
            if (this.value <= 1) {
              return this.value + ' month';
            }
            return this.value + ' months';
          }
        }
      },
    };

    return(
      <div>
        <ReactHighcharts config={config} />
        <div style={{ display: 'flex', justifyContent: 'center', marginTop: 30 }}>
          <RangeSlider
            label="Risk Value"
            defaultValue={8}
            min={1}
            max={62}
            handleChange={this.handleChange}
          />
        </div>
      </div>
    )
  }
}
like image 982
Arslan Tariq Avatar asked Oct 18 '17 07:10

Arslan Tariq


1 Answers

So, I have found a workaround. It is working perfectly. I am getting the chart by ref and then set a new data using setData. This only updates the data rather than re-rendering the whole chart component. And I am using component lifecycle method shouldComponentUpdate to stop the re-rendering of the component. Here is the related code:

class ContributionRiskGraph extends React.PureComponent {
  constructor() {
    super();

    this.state = {
      riskValue: 8.161736
    };

    this.handleChange = this.handleChange.bind(this);
  }

  shouldComponentUpdate(nextProps, nextState) {
    if(this.state.riskValue !== nextState.riskValue) {
      return false;
    }
  }

  handleChange(value) {
    this.setState({
      riskValue: value
    });

    let riskValue = this.state.riskValue / 100;
    let chart = this.crg.getChart();
    chart.series[0].setData(getGraphPlotData(riskValue, 'lowerBound'), true);
    chart.series[1].setData(getGraphPlotData(riskValue, 'expectedValue'), true);
    chart.series[2].setData(getGraphPlotData(riskValue, 'upperBound'), true);
  }

  render() {
    // other code
    return(
      <div>
        <ReactHighcharts config={config} ref={a => this.crg = a} />
        <div style={{ display: 'flex', justifyContent: 'center', marginTop: 30 }}>
          <RangeSlider
            label="Risk Value"
            defaultValue={8}
            min={1}
            max={62}
            handleChange={this.handleChange}
          />
        </div>
      </div>
    ) 
  }
}
like image 138
Arslan Tariq Avatar answered Nov 14 '22 22:11

Arslan Tariq