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>
);
}