Profer
Profer

Reputation: 633

Dynamically high chart rendering not working

I have parent component in which I have used the parent highchart component. Something like this

class MobHome extends Component {
  render() {
    return(
      <Link to="/graphdetails">
        <AreaSplineChart
          id="1keyTotalVisitor"
          key="keyTotalVisitor"
          className="graph-visitor"
          title="<strong>Total Visitors</strong>"
          subtitle={`This is all the users that have visited your <br/> site.
             <br/><span style='font-size:60px; color: #5BC0BE; font-weight:600'>
             ${ analyticsData.totalVisitors }</span>`}
          data={_.get(analyticsData, 'totalVisitorsGraphData', []).map(t => t.count)}
          categories={_.get(analyticsData, 'totalVisitorsGraphData', []).map(t => t._id)}
          filterType={this.state.filterType}
          graphData={_.get(analyticsData, 'totalVisitorsGraphData', [])}
        />
      </Link>
    )
  }
}

And my highchart(child) component looks Something like this

componentWillReceiveProps (np) {
  if (this.props.data !== np.data) {
    this.highChartFunction(np)
  }
}
class AreaSplineChart extends Component {
  highChartFunction () {
    const { title, subtitle, id, data, categories, graphData } = this.props
    console.log(id)
    Highcharts.chart(String(id), {
      //... options
    })
  }

  render () {
    const { id } = this.props
    console.log(id)
    return (
      <div key={id} id={id}/>
    )
  }
}
export default AreaSplineChart

Now the issue is working correct in my development mode but gives error in production mode.

Error: Highcharts error #13: www.highcharts.com/errors/13

I have console logs everywhere I am sure my ids first renders and then my function being called. But still I am getting the issue. Is there any with gatsby production build or I am doing something wrong here?

Thank you!!!

Upvotes: 0

Views: 535

Answers (1)

user6612182
user6612182

Reputation:

The error given by the Highchart library means that it could not find the div with the id you provided. It would seem that componentWillReceiveProps is called before render.

I would recommend you call your highChartFunction inside the componentDidMount lifecycle method and save the Chart instance to a class property to access it later. componentDidMount is called right after first call to render, so the element should be created at this point.

componentDidMount() {
    this.highChartFunction();
}

highChartFunction () {
    const { title, subtitle, id, data, categories, graphData } = this.props;

    this.chart = Highcharts.chart(String(id), {
      //... options
    });
}

If you want to handle updates to the props I would recommend using componentDidUpdate, as componentWillReceiveProps is marked for deprecation and is planned to be removed in React 17. Also there seemed to be some bugs with it. componentDidUpdate gets the previous props as an argument so you can check if a update is needed:

componentDidUpdate(prevProps) {
    if ("somehow prevProps and this.props is different") { // Replace with check
        this.chart.update({
            // new options
        }, /* Here is an argument to set if the chart should be rerendered, you can set it if necessary */);
    }
}

Also don´t forget to set the componentWillUnmount lifecycle method to destroy the chart:

componentWillUnmount() {
    this.chart.destroy();
}

Personal recommendation: I would not use the id to set the chart, but instead use Refs. Those are references to the component which is in my opinion much better than an id lookup.

constructor() {
    this.chartContainer = React.createRef();
}

highChartFunction() {
    /* ... */
    Highcharts.chart(this.chartContainer.current, { ... });
}

render() {
    const { id } = this.props;
    return (<div key={id} id={id} ref={this.chartContainer} />)
}


Here is a minimal example with all I have mentioned here.

Upvotes: 1

Related Questions