First of all, I'm new to React and the whole Frontend thing, so this is probably something obvious.
I'm writing a simple choropleth map in React using react-leaflet, but I'm facing some performance issues.
My case is very similar to the one you can see here:
https://codepen.io/hazmi/pen/JjoyONo
If you add a console.log statement to the style method and check the console you can see that the style method is called for every feature on the map on every mouseover or mouseout event.
In my case it is even worse, as style is called twice for every feature on the map.
Unfortunately, this is a huge performance issue on bigger maps and also causes all kinds of side effects.
I assume the style method is called because the <GeoJSON> layer is re-rendered all the time because of the state change caused by the 2 mouse event handlers setting the selected variable. My case is very similar, just the component structure is a bit more complex.
More components rely on the value of the selected variable, so I need that to be set on hover and reset on mouseout.
const colors = [ /* constant array */ ];
function Map() {
const [hoveredCountry, setHoveredCountry] = useState(null);
const [statsData, setStatsData] = useState(null);
...
const highlightFeature = e => {
let layer = e.target;
setHoveredCountry({ stats: statsData[layer.feature.properties.iso_a3] });
}
const resetHighlight = e => {
setHoveredCountry(null);
}
const onEachFeature = (feature, layer) => {
layer.on({
mouseover: highlightFeature,
mouseout: resetHighlight
});
}
const style = feature => { /* calculate and return style object */ }
...
return (
<MapContainer center={[40, 0]}>
<TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" attribution='© <a href="https://www.openstreetmap.org/copyright" target="blank">OpenStreetMap</a> contributors' />
<ZoomControl position='bottomleft' />
<GeoJSON data={countries} style={style} onEachFeature={onEachFeature} ref={geoJsonLayer}>
<InfoTooltip scope={dataScope} hoveredCountry={hoveredCountry} />
</GeoJSON>
<InfoBox data={selectedCountry} scope={dataScope} open={infoBoxOpen} closeHandler={handleInfoBoxClosed} />
<MapControls options={dataScopes} value={dataScope} changeHandler={handleDataScopeChange} />
<Legend scope={dataScope} colors={colors} hoveredCountry={hoveredCountry} />
</MapContainer>
);
}
In my case shown above, the Legend and InfoTooltip both depend on the hoveredCountry state variable similarly how the tooltip uses the selected state variable in the CodePen example.
How can I avoid these unnecessary re-renders? Is this the issue to begin with?