2

I am not sure if this is an issue of react-leaflet-markercluster, react-leaflet, leaflet, react, or my code.

I have a map with several thousand markers and I am using react-leaflet-markercluster for marker clustering. If I need to update a global state of MapComponent, there is 1-3 seconds delay when this change is reflected.

I created a codesandox with 5000 markers and you can see there 2 use cases with performance issues:

1.) MapComponent is inside react-reflex element, that allows resizing panel and propagates new dimensions (width, height) to MapComponent. If width and height are changed, mapRef.invalidateSize() is called to update map dimensions. Resizing is extremely slow.

2.) If user clicks on Marker, global state selected is updated. It is a list of clicked marker ids. Map calls fitBounds method to focus on clicked marker and also marker icon is changed. There is around 1 second delay.

In my project, if I need to change a MapComponent state, it takes 2-3 seconds in dev mode when changes are reflected and it is just a single rerender of MapComponent and its elements (markers).

I took a look at Chrome performance profile and it seems like most time is spent in internal React methods.

It is possible to fix this by preventing rerendering using memo, which is similar to shouldComponentUpdate, but it makes whole code base too complicated. preferCanvas option doesn't change anything. I am wondering what is a good way to fix these issues.

1 Answer 1

6
+50

The main problem I identified in your code is that you re-render the whole set of marker components. If you memoize the generation of those, you achieve a good performance boost; instead of running the .map in JSX, you can store all the components in a const; this way, the .map won't run on every render.

from this

...
   <MarkerClusterGroup>
     {markers.map((marker, i) => {
...

to something like this

  const markerComponents = React.useMemo(() => {
    return markers.map((marker) => {
      return (
        <MarkerContainer .../>
      );
    });
  }, [markers, onMarkerClick]);

  return (
    <>
      <MarkerClusterGroup>{markerComponents}</MarkerClusterGroup>
    </>
  );

The second refactor I tried is changing the way you select a marker. Instead of determining the selected prop from the selected array for each marker, I put a selected field on every marker object and update it when selecting a marker. Also, I add the position to the onClickHandler args to avoid looking for that in the markers array.

There are some other tweaks I don't explain here so please check my codesandbox version.

https://codesandbox.io/s/dreamy-andras-tfl67?file=/src/App.js

0

Not the answer you're looking for? Browse other questions tagged or ask your own question.