Search code examples
reactjshighchartsreact-hooksuse-effectreact-state

Function does not work on first render instead the series is generated after the subsequent renders


My function generateSeriesDataWithColor() seems like it does not load before the component or page renders.

So, the seriesWithColor should get the data genrated by generateSeriesDataWithColor() right away when the component is loaded but it does not get generated at the first render, instead if the component is rendered again, the colors and the graph shows up.

    import HighchartsReact from "highcharts-react-official";
    import Highcharts from "highcharts";
    import './SkillsGraph.scss';
    import { Col, Row } from "react-bootstrap";
    import HeadingMain from "../../Heading/HeadingMain/HeadingMain";

    export default function SkillsGraph(){

    const skills = ['HTML5/CSS3/JS', 'Java11', 'PHP', 'MySql', 'MongoDB', 'ReactJS', 'ExpressJS'];
    const series = {
        name: 'Skill Level', 
        data: [ 10, 9.5, 7, 9.5, 8, 8.5, 8]
    };

    const seriesWithColor = generateSeriesDataWithColor(series); // This is where the series is assigned to the var
    
    // Randomly generate colors 
    function generateRandomColor(){
        let maxVal = 0xFFFFFF; // 16777215
        let randomNumber = Math.random() * maxVal; 
        randomNumber = Math.floor(randomNumber);
        randomNumber = randomNumber.toString(16);
        let randColor = randomNumber.padStart(6, 0);   
        return `#${randColor.toUpperCase()}`
    }

    // Generate the data with random conlor
    function generateSeriesDataWithColor(seriesData){

        const data = seriesData.data;

        const dataArray = data.map((item) => {
            let color = generateRandomColor();
            while(color === "#FFFFFF"){
                color = generateRandomColor();
            }

            let dataObj = {
                y: item,
                color: color
            }

            return dataObj;
        })


        let seriesWithColor = {
            name: 'Skill Level',
            data: dataArray
        }
    
        return seriesWithColor; //This is from where the data/series is returned
    }

    // Options for the graph
    let options = {
        chart: {
            type: 'bar',
            height: 400
        },
        title: {
            align: 'left',
            text: 'Skills represented'
        },
        xAxis: {
            categories: skills,
            visible: true,
            type: 'Skills categorised',
            title: {
                text: null
            }
        },
        yAxis: {
            min: 0,
            max: 10,
            title: {
                text: 'Skill Level',
                align: 'high'
            },
            labels: {
                overflow: 'justify'
            }
        },
        plotOptions: {
            bar: {
                dataLabels: {
                    enabled: false
                }
            },
            column: {
                colorByPoint: true
            }
        },
        colors: [
            '#ff0000',
            '#00ff00',
            '#0000ff',
            '#0000ff',
            '#0000ff',
            '#0000ff',
            '#0000ff'
        ],
        legend: {
            enabled: true
        },
        credits: {
            enabled: false
        },
        series: seriesWithColor // This is where the generated data/series is used
    } 

    return (
        <Row>
            <Col md={3}>
                <HeadingMain name="This is Legend"></HeadingMain>
            </Col>
            <Col md={9}>
                <HighchartsReact highcharts={Highcharts} options={options} className="chart"></HighchartsReact>
            </Col>
        </Row>
    )
    } 

Does anyone have a solution for this?

I tried using useEffect hook to complete the wanted task but it gives an error message - 'React Hook useEffect has missing dependencies: 'generateSeriesDataWithColor' and 'series'. Either include them or remove the dependency array react-hooks/exhaustive-deps'. (Please check the code below)

const [seriesWithColor, setSeries] = useState(null);

useEffect(() => {
    generateSeriesDataWithColor(series)
    .then(data => setSeries(data))
    .catch(err => console.log(err));
}, []);

Solution

  • Series needs to be an array of objects instead of a single object:

      let options = {
        ...,
        series: [seriesWithColor] // This is where the generated data/series is used
      };
    

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

    API Reference: https://api.highcharts.com/highcharts/series