1

I am using React Leaflet and react-leaflet-markercluster. I have a lot of markers and if parent's state is changed, marker cluster rerendering takes longer time. For this reason, cluster components are memoized.

When I click on a polygon, I want to delete it's marker from map and markercluster. I am looking for a way to do it without rerendering markercluster. I tried this code, but it doesn't work:

React.useEffect(() => {
    Object.keys(mapRef?._layers).forEach(function (key) {
      const leafletLayer = mapRef?._layers[key];

      if (typeof leafletLayer?.getAllChildMarkers === "function") {
        const allMarkers = leafletLayer.getAllChildMarkers();
        allMarkers.forEach((marker) => {
          const dataId = marker.options.id;
          const foundMarker = props.selected.find(
            (selectedAsset) => selectedAsset === dataId
          );
          if (foundMarker) {
            console.log("remove marker from map", marker);
            mapRef.removeLayer(marker);
          }
        });
      }
    });
  }, [mapRef, props.selected]);

codesandbox

Matt
  • 8,195
  • 31
  • 115
  • 225
  • I spent some time with this, tough question. I think the secret lies in being able to get a ref to the underlying leaflet element for the markercluster (easy), and then get an array of all the markers in that cluster layer. I can't seem to figure out how to do that though. If you know how to take an `L.MarkerCluster` and get an array of all the markers, I think we can do this, by removing the markers directly from the leaflet element and leaving react out of it. It seems `getAllChildMarkers` is only available from within an event callback? – Seth Lutske Mar 09 '21 at 16:30
  • @SethLutske thanks for taking a look at this. After all, I just removed `react-leaflet-markercluster` wrapper and now I am using only `Leaflet.markercluster`. I am storing markercluster reference in a variable which is out of react component. I am able to delete markers in `React.memo` function of `MapElements` component where I can access markercluster reference and delete markers. – Matt Mar 09 '21 at 16:57
  • I'm glad that works for you. I'm sure there's a way to do in within the component, but with react-leaflet-v3, we end up digging into the underlying leaflet components anyway. Its a delicate balance – Seth Lutske Mar 09 '21 at 16:59
  • @SethLutske I am working on a project where I need to integrate Leaflet with leaflet-geoman in a React project with thousands of geojsons and markers, which should be draggable and editable. It's super tricky to make all these things working together. – Matt Mar 09 '21 at 17:04
  • Sounds badass, post it here when its done! if possible. If you want the popups to be editable too, you can check out my [react-leaflet-editable-popup](https://github.com/slutske22/react-leaflet-editable-popup), though I'm not sure how that would integrate with markercluster in the way you're using it. Good luck! – Seth Lutske Mar 09 '21 at 17:41
  • @SethLutske thanks, if I need it, I will use your editable popup library. I will definitely share and make public some code snippets later, but now I am too busy – Matt Mar 09 '21 at 19:57

2 Answers2

0

I decided to remove react-leaflet-markercluster wrapper and use only Leaflet.markercluster library, which I use like this:

const mcg = L.markerClusterGroup({
    chunkedLoading: true,
    showCoverageOnHover: false,
});

const MarkersCluster = ({ markers }) => {
    const { map } = useLeaflet();
    useEffect(() => {
        mcg.clearLayers();
        const markerList = markers.map(({ coords }) => {
            return L.marker(new L.LatLng(coords.latitude, coords.longitude), {
                icon: YOUR_ICON,
            });
        });

        mcg.addLayers(markerList);
        map.fitBounds(mcg.getBounds());
        map.addLayer(mcg);
    }, [markers, map]);


    return null;

};


export default MarkerCluster;

and use it:
<MarkerCluster marker={my_markers} />

Now, I can access cluster reference in React.memo of MapElements and remove markers and prevent rerendering whole cluster.

Matt
  • 8,195
  • 31
  • 115
  • 225
0

Instead of removing the marker from the rendered cluster, remove it from the source, i.e the GEOJSON data and then remove the clusterlayer and re-apply it.

Its a pretty unknown fact that render from new is a lot quicker than re-rendering.

Your old way is ok for small amounts of markers but not for 25K+

Dharman
  • 30,962
  • 25
  • 85
  • 135
JulesUK
  • 359
  • 2
  • 11