'React-leaflet performance issue, prevent GeoJSON re-render

I have the following issue:

I would like to create a simple choropleth map using react-leaflet's GeoJSON component. I also want to have a tooltip that shows a value on hover over a GeoJSON feature. The problem is performance. A CodePen example can be found here: https://codepen.io/timester-the-typescripter/pen/gOXGKOY

I attach event handlers to each GeoJSON feature and set a state variable in my "main" component that holds the value for the currently hovered area.

const [selected, setSelected] = React.useState(null);

My tooltip relies on that state variable to show its value. Because every mouse hover event causes main component state change, the GeoJSON component gets re-rendered all the time. This is not a huge problem in the CodePen example, but for a full world map it is unfortunately.

I assume that the state change causes this because if I comment out the 2 setSelected lines (line 55, and line 67 in CodePen), the re-renders (calls to createGeoJSON ) stop, and the event handlers run a lot faster as the profiler pictures show below.

Mouseout event with state change: Mouseout event with state change

Mouseout event with state change commented out: Mouseout event with state change commented out

I tried many solutions with no success. For example I think I can't memoize the GeoJSON component because the Tooltip must be its child and that depends on the state of the main component.

In the future I want to add more components depending on the hovered state variable like a legend, etc.. and maybe that variable will be a bit more complex than a simple number too.

What options do I have here? I had another stackowerflow question about this, but then I did not understand the problem completely, so it was not super focused. I'm at the point where I'm thinking about rewriting it in Angular. I found react and react-leaflet very pleasant to work with, until this issue came up.



Solution 1:[1]

I got help from this reddit comment https://www.reddit.com/r/reactjs/comments/std46f/comment/hx3yq34/?utm_source=share&utm_medium=web2x&context=3

The solution I applied based on this is not to use the Tooltip as a child component, but bind a tooltip to each layer in the onEachFeature method.

const onEachFeature = useCallback((feature, layer) => {
    layer.bindTooltip(feature.properties.COUNT, {sticky: true});
    ...
    

This way I could also wrap the GeoJSON component in a useMemo() as there were no longer dependencies on the selected state. I also wrapped the style and onEachFeature functions in useCallback().

This combination solved the issue!

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Imre Tömösvári