jay queue
jay queue

Reputation: 415

Dynamically updating a highcharts object after data refresh in React

I am trying to build an employee org chart using Highcharts network graph but I'm running into errors. The idea is simple. I want to render an initial chart with the president and a few of their direct reports. After that, if the user clicks on a node in the chart, I want to pull data for that individual's direct reports and update the graph with the children nodes for that individual's subordinates. The back end API for the data pull is working fine

Here is my code:

import React, { useState, useEffect, useRef } from 'react';
import axios from 'axios';
import Highcharts from 'highcharts';
import HighchartsReact from 'highcharts-react-official';

import networkgraph from "highcharts/modules/networkgraph";
networkgraph(Highcharts);

const Employees3 = () => {

    const chartComponent = useRef(null); // reference to chart obj 
    const [nodeData, setNodeData] = useState([
        { 'id': 'A', dataLabels: { enabled: true }, marker: { radius: 11, fillColor: 'red' } },
        { 'id': 'P', dataLabels: { enabled: true } },
        { 'id': 'K', dataLabels: { enabled: true } },
        { 'id': 'S', dataLabels: { enabled: true } },
        { 'id': 'D', dataLabels: { enabled: true } },
    ]);

    const [linkData, setLinkData] = useState([
        { 'from': 'D', 'to': 'A' },
        { 'from': 'S', 'to': 'A' },
        { 'from': 'K', 'to': 'A' },
        { 'from': 'P', 'to': 'A' }
    ]);


    const [chartOptions, setChartOptions] = useState({
        chart: {
            type: 'networkgraph',
            plotBorderWidth: 1,
        },
        title: {
            text: 'Phrasal verbs'
        },
        subtitle: {
            text: 'Integration: ' + 'euler'
        },
        credits: false,
        plotOptions: {
            networkgraph: {
                layoutAlgorithm: {
                    enableSimulation: false,
                    integration: 'euler',
                    linkLength: 25,
                },
                keys: ['from', 'to'],
                marker: {
                    radius: 5,
                    lineWidth: 1
                }
            },
            series: {
                point: {
                    events: {
                        click: function () {
                            var name = this.id.replace(' ', '%20');
                            axios.get('api/employee_data/' + name)
                                .then(response => { 
                                    setNodeData(nodeData.concat(response.data.nodes));
                                    setLinkData(linkData.concat(response.data.links));
                                     chartComponent.current.chart.redraw();
                                }).catch( err => {
                                })
                            },
                    }
                }
            }
        },
        series: [{
            allowPointSelect: true,
            nodes: nodeData,
            data: linkData,
        }]
    });

    console.log('nodes: ', nodeData)
    console.log('links: ', linkData)
    
    return (
        <div>
            <HighchartsReact
                highcharts={Highcharts}
                options={chartOptions}
                containerProps={{ style: { height: 700 } }}
                allowChartUpdate = {true}
                ref={chartComponent}
            />
        </div>
    )
};

export default Employees3;

I'm using a function on the series.event.click object to render a GET call to pull the child nodes and links from the server and update my state for nodeData and linkData. When I do a console log of these state arrays, it is showing me the right data. I then try to rerender the chart object with the updated data using the redraw method on the chart reference. The problem is that the chart is not rerendering with the new data using this approach. Instead it continues to show the old data.

Any thoughts on what I may be doing wrong here and how I can rerender the chart after the data update?

Much appreciated

EDIT (2-6-21)

axios.get('api/employee_data/' + name)
    .then(response => {

        setNodeData((prevState) => {
            return [...prevState, ...response.data.nodes]
        });
        setLinkData((prevState) => {
            return [...prevState, ...response.data.links]
        });

        setChartOptions({
            series: [{
                nodes: nodeData, //doesnt work
                data: linkData //doesnt work
                nodes: response.data.nodes,  // works but doesn't give me what I need
                data: response.data.links,
            }]
        });
    });

Upvotes: 1

Views: 3454

Answers (1)

ppotaczek
ppotaczek

Reputation: 39079

You need to update state which is directly related with a chart component options props:

    plotOptions: {
        ...,
        series: {
            point: {
                events: {
                    click: function () {
                        var name = this.id.replace(' ', '%20');
                        axios.get('api/employee_data/' + name)
                            .then(response => { 
                                setChartOptions({
                                    series: [{
                                        nodes: response.data.nodes,
                                        data: response.data.links
                                    }]
                                });
                            }).catch( err => {})
                        }
                }
            }
        }
    }

Live demo: https://codesandbox.io/s/highcharts-react-demo-ngq7w?file=/demo.jsx

Upvotes: 1

Related Questions