Home > Back-end >  How to prevent a Map from re-rendering when a state variable changes (React) (Fusion Charts)
How to prevent a Map from re-rendering when a state variable changes (React) (Fusion Charts)

Time:12-25

I have this problem where every time a user hovers there mouse pointer over my map of the USA, the map renders again. (Visually, it flashes on the screen and it looks terrible).

This is because I have an 'entityRolloever' event which causes a state variable to change.

      entityRollover: function(event, data){
        setHoveredState(data.label)
      }

How I understand it is, when a React component (i.e. my map) changes state, it re-renders.

But what I want is, when a user hovers over a U.S. State, I want the state that is being hovered over to show up in a separate text box (without the whole map re-rendering).

I have searched around, and I have found some other React hooks which could solve this. They are useRef, useMemo, and useCallback. However, I'm not sure how they would solve my problem as I have never used them before.

If you want to recreate my problem, create a basic React app

npx create-react-app

Install the following packages

npm i fusioncharts react-fusioncharts fusionmaps

Then grab the code in my jsfiddle and paste it into 'App.js'

https://jsfiddle.net/cmascardo5/s8trame5/

CodePudding user response:

There are a couple of ways to resolve this issue. I chose to replace useState() hook with useRef() since it matches your case perfectly.

useState() is a hook used in functional components to re-render components on state change, but in your case this is NOT something that we want. We want to track the updates without re-rendering the components. To achieve this, we use useRef(). When we use useRef() for the updates it will not fire re-rendering unlike useState().

In your code, I commented out the {hoveredState} you had to avoid re-rendering. Then I created a p element and ref it with useRef(). Then on the entityRollove method, I update the innerText of the referenced p element. This way we are tracking the updates without re-rendering. It is simpler to see the code, I did comment on the lines I added: (paste it in your App.js)

import React from 'react';
import './App.css';

import ReactFC from 'react-fusioncharts';
import FusionCharts from 'fusioncharts';
import FusionMaps from 'fusioncharts/fusioncharts.maps';
import USA from 'fusionmaps/maps/fusioncharts.usa';
import FusionTheme from 'fusioncharts/themes/fusioncharts.theme.fusion';
import { Grid, Paper } from '@material-ui/core';
import { useState } from 'react';
import { useRef } from 'react';

ReactFC.fcRoot(FusionCharts, FusionMaps, USA, FusionTheme);

export default function App({}) {
  const [hoveredState, setHoveredState] = useState('All States');
  let test1 = 'test';
  // const hoveredState =useRef("All states");

  // Here we are using UseRef() to get a reference to an element we want to use to show each State's names
  const paragraphEl = useRef(null);

  const colorrange = {
    minvalue: '20',
    code: '#00A971',
    gradient: '1',
    color: [
      {
        minvalue: '20',
        maxvalue: '40',
        code: '#EFD951',
      },
      {
        minvalue: '40',
        maxvalue: '60',
        code: '#FD8963',
      },
      {
        minvalue: '60',
        maxvalue: '80',
        code: '#D60100',
      },
    ],
  };
  const data = [
    {
      id: 'HI',
      value: '70.0',
    },
    {
      id: 'DC',
      value: '52.3',
    },
    {
      id: 'MD',
      value: '54.2',
    },
    {
      id: 'DE',
      value: '55.3',
    },
    {
      id: 'RI',
      value: '50.1',
    },
    {
      id: 'WA',
      value: '48.3',
    },
    {
      id: 'OR',
      value: '48.4',
    },
    {
      id: 'CA',
      value: '59.4',
    },
    {
      id: 'AK',
      value: '26.6',
    },
    {
      id: 'ID',
      value: '44.4',
    },
    {
      id: 'NV',
      value: '49.9',
    },
    {
      id: 'AZ',
      value: '60.3',
    },
    {
      id: 'MT',
      value: '42.7',
    },
    {
      id: 'WY',
      value: '42.0',
    },
    {
      id: 'UT',
      value: '48.6',
    },
    {
      id: 'CO',
      value: '45.1',
    },
    {
      id: 'NM',
      value: '53.4',
    },
    {
      id: 'ND',
      value: '40.4',
    },
    {
      id: 'SD',
      value: '45.2',
    },
    {
      id: 'NE',
      value: '48.8',
    },
    {
      id: 'KS',
      value: '54.3',
    },
    {
      id: 'OK',
      value: '59.6',
    },
    {
      id: 'TX',
      value: '64.8',
    },
    {
      id: 'MN',
      value: '41.2',
    },
    {
      id: 'IA',
      value: '47.8',
    },
    {
      id: 'MO',
      value: '54.5',
    },
    {
      id: 'AR',
      value: '60.4',
    },
    {
      id: 'LA',
      value: '66.4',
    },
    {
      id: 'WI',
      value: '43.1',
    },
    {
      id: 'IL',
      value: '51.8',
    },
    {
      id: 'KY',
      value: '55.6',
    },
    {
      id: 'TN',
      value: '57.6',
    },
    {
      id: 'MS',
      value: '63.4',
    },
    {
      id: 'AL',
      value: '62.8',
    },
    {
      id: 'GA',
      value: '63.5',
    },
    {
      id: 'MI',
      value: '44.4',
    },
    {
      id: 'IN',
      value: '51.7',
    },
    {
      id: 'OH',
      value: '50.7',
    },
    {
      id: 'PA',
      value: '48.8',
    },
    {
      id: 'NY',
      value: '45.4',
    },
    {
      id: 'VT',
      value: '42.9',
    },
    {
      id: 'NH',
      value: '43.8',
    },
    {
      id: 'ME',
      value: '41.0',
    },
    {
      id: 'MA',
      value: '47.9',
    },
    {
      id: 'CT',
      value: '49.0',
    },
    {
      id: 'NJ',
      value: '52.7',
    },
    {
      id: 'WV',
      value: '51.8',
    },
    {
      id: 'VA',
      value: '55.1',
    },
    {
      id: 'NC',
      value: '59.0',
    },
    {
      id: 'SC',
      value: '62.4',
    },
    {
      id: 'FL',
      value: '70.7',
    },
  ];
  // };
  FusionCharts.ready(function () {
    var chart = new FusionCharts({
      type: 'maps/usa',
      caption: 'Average Temperature of US States',
      subcaption: '1979 - 2000',
      entityfillhovercolor: '#F8F8E9',
      numbersuffix: '°F',
      showlabels: '1',
      borderthickness: '0.4',
      theme: 'fusion',
      entitytooltext:
        '<b>$lname</b> has an average temperature of <b>$datavalue</b>',
      renderAt: 'chart-container',
      width: '700',
      height: '500',
      colorrange: colorrange,
      dataFormat: 'json',
      dataSource: {
        chart: {
          caption: 'Average Temperature of US States',
          subcaption: '1979 - 2000',
          entityfillhovercolor: '#F8F8E9',
          numbersuffix: '°F',
          showlabels: '1',
          borderthickness: '0.4',
          theme: 'fusion',
          entitytooltext:
            '<b>$lname</b> has an average temperature of <b>$datavalue</b>',
          // "animation":0,
          // "defaultAnimation":0
        },
        colorrange: colorrange,
        data: data,
      },
      events: {
        preRender: function (event, data) {
          // code to be executed before the chart is re-rendered
        },
        postRender: function (event, data) {
          // code to be executed after the chart is re-rendered
        },
        entityRollover: function (event, data) {
          console.log('test..'   data.label);
          // Here we get a reference to the paragraph element and set its innerText to be the state's name we are hovering on
          paragraphEl.current.innerText = data.label;
        },
      },
    }).render();
  });
  return (
    <Grid container spacing={2}>
      <Grid item xs={9}>
        <div id="chart-container"></div>
      </Grid>
      <Grid item xs={3}>
        // we create a p element that will hold state's name on hover
        <p ref={paragraphEl}></p>
        {/* {hoveredState} */}
      </Grid>
    </Grid>
  );
}
  • Related