Cluster from googlemaps/markerclusterer don't load on first render

95 Views Asked by At

I'm using React with TypeScript and { MarkerClusterer } from "@googlemaps/markerclusterer to have Clusters in my map, but my problem is that the first time I render the Google Map, the Clusters are not showing, but if I re-render the view, the Clusters appear (f5).

I tried using console.log() to see if the options I send to the Clusters are sent properly, and yes they are, so I think that the problem could be in the Google library

This is my Cluster component:

import React from "react";
import { Countryside } from "../../shared/types";
import Point from "../../assets/icons/svg/EstablishmentsMapPage/point.svg";
import { MarkerClusterer } from "@googlemaps/markerclusterer";

interface ClusterProps {
  markers: Countryside[];
  isVisible: boolean;
  map?: google.maps.Map;
  onClick?: (...args: any) => Promise<void>;
}

const Cluster: React.FC<ClusterProps> = ({
  markers,
  onClick,
  map,
  isVisible,
}) => {
  const [clusters, setClusters] = React.useState<MarkerClusterer>();
  const [markersForCluster, setMarkersForCluster] =
    React.useState<google.maps.Marker[]>();

  React.useEffect(() => {
    if (!clusters) {
      const newMarkers = markers.map((value, i) => {
        console.log("value", value)
        const marker: any = new google.maps.Marker({
          position: {
            lat:
              value.countryside_lat != undefined
                ? parseFloat(value.countryside_lat)
                : parseFloat(value.countryside_lat),
            lng:
              value.countryside_lon != undefined
                ? parseFloat(value.countryside_lon)
                : parseFloat(value.countryside_lon),
          },
          visible: isVisible,
          icon: Point,
          zIndex: Number(google.maps.Marker.MAX_ZINDEX) + i,
          label: {
            className: "map-marker",
            color: "#33333",
            fontFamily: "'Poppins', sans-serif",
            fontWeight: "600",
            fontSize: "1.2rem",
            text: "" + value.count_silobags,
          },
        });

        const infoWindow = new google.maps.InfoWindow({
          content: `
            <div style="background-color: #ffffff;
            border-radius: 8px;
            box-shadow: 0px 2px 6px rgba(0, 0, 0, 0.15);
            padding: 5px;
            font-family: 'Poppins', sans-serif;">
              <h3 style="font-size: 18px;
              font-weight: bold;
              color: #333333;
              margin-bottom: 8px;">${value.countryside_name}</h3>
            </div>
          `,
        });

        if (infoWindow) {
          marker.addListener("mouseover", () => {
            infoWindow.open({ anchor: marker, map, shouldFocus: false });
          });
          marker.addListener("mouseout", () => {
            infoWindow.close();
          });
        }

        return marker;
      });
      if (newMarkers.length === 0) return;
      setMarkersForCluster(newMarkers);
      setClusters(
        new MarkerClusterer({
          markers: newMarkers,
          map,
          renderer: {
            render: ({ count, position, markers }) => {
              const finalCount: any =
                markers && markers.length > 0
                  ? [...markers]
                      .map((val: any) => {
                        return val.getLabel()?.text;
                      })
                      .reduce(
                        (partialSum: any, a: any) => partialSum + parseInt(a),
                        0
                      )
                  : 0;
              return new google.maps.Marker({
                label: {
                  text: String(finalCount),
                  className: "map-marker",
                  color: "#33333",
                  fontFamily: "'Poppins', sans-serif",
                  fontWeight: "600",
                  fontSize: "1.2rem",
                },
                position: {
                  lat: position.lat(),
                  lng: position.lng(),
                },
                visible: isVisible,
                map,
                icon: Point,
                zIndex: Number(google.maps.Marker.MAX_ZINDEX) + count,
              });
            },
          },
        })
      );
    }

    return () => {
      if (clusters) {
        markersForCluster?.map((value) => value.setMap(null));
        clusters.clearMarkers();
        setClusters(undefined);
      }
    };
  }, [clusters, markers, isVisible]);

  React.useEffect(() => {
    if (map && markers && markersForCluster) {
      google.maps.event.clearListeners(map, "onClick");

      markersForCluster.forEach((value, i) => {
        value.setVisible(isVisible);
        if (onClick) {
          value.addListener("click", async () => {
            const currentZoom = map.getZoom();
            await onClick(markers[i].countryside_id);
            map.panTo(value.getPosition() as google.maps.LatLng);
            if (currentZoom && currentZoom < 12) map.setZoom(12);
          });
        }
      });
    }
  }, [clusters, onClick, isVisible]);

  return null;
};

export default Cluster;

0

There are 0 best solutions below