I am using this library: @vis.gl/react-google-maps
. I have seen the following video which implements a map with clustering markers.
https://www.youtube.com/watch?v=PfZ4oLftItk
therefore I implemented the following components:
import { APIProvider, Map } from "@vis.gl/react-google-maps";
import PropTypes from "prop-types";
import React, { useState } from "react";
import { useGetAppContext } from "../associated-garages/hooks/use-get-app-context";
import { appType, googleMapsApiKey, googleMapsIcons, googleMapsVariables } from "./GoogleMapUtilities";
import CustomMarkers from "./CustomMarkers";
function CustomMap({ typeOfApp }) {
const [centerLatLng, setCenterLatLng] = useState(googleMapsVariables.CENTER);
const [hoveredMarker, setHoveredMarker] = useState(null);
const {
state: { currentResults, selectedMarker },
garageDispatch,
} = useGetAppContext(appType.GARAGES);
return (
<div style={{ height: "100vh", width: "100%" }}>
<APIProvider apiKey={googleMapsApiKey.DEV}>
<Map
mapId="DEMO_MAP_ID"
defaultCenter={googleMapsVariables.CENTER}
defaultZoom={googleMapsVariables.ZOOM}
>
<CustomMarkers points={currentResults} typeOfApp={typeOfApp} />
</Map>
</APIProvider>
</div>
);
}
CustomMap.propTypes = {
typeOfApp: PropTypes.string.isRequired,
};
export default CustomMap;
and the CustomMarkers component:
import { MarkerClusterer } from "@googlemaps/markerclusterer";
import { AdvancedMarker, useMap } from "@vis.gl/react-google-maps";
import PropTypes from "prop-types";
import React, { useEffect, useRef, useState } from "react";
import { useGetAppContext } from "../associated-garages/hooks/use-get-app-context";
import { GarageActionTypes, garageTypeCode, motorTypeCode } from "../associated-garages/utilities/TextUtilities";
import { appType, googleMapsIcons } from "./GoogleMapUtilities";
import markerShape from "./common/propTypes";
const CustomMarkers = ({ points, typeOfApp }) => {
const map = useMap();
const [markers, setMarkers] = useState({});
const clusterer = useRef(null);
const [isHovered, setIsHovered] = useState(false);
const [isClicked, setIsClicked] = useState(false);
const {
state: { selectedMarker },
garageDispatch,
} = useGetAppContext(appType.GARAGES);
useEffect(() => {
if (!map) return;
if (!clusterer.current) {
clusterer.current = new MarkerClusterer({ map });
}
}, [map]);
useEffect(() => {
clusterer.current?.clearMarkers();
clusterer.current?.addMarkers(Object.values(markers));
}, [markers]);
const setMarkerRef = (marker, key) => {
if (marker && markers[key]) return;
if (!marker && !markers[key]) return;
setMarkers((prev) => {
if (marker) {
return { ...prev, [key]: marker };
} else {
const newMarkers = { ...prev };
delete newMarkers[key];
return newMarkers;
}
});
};
return (
<React.Fragment>
{points.map((point) => (
<React.Fragment key={point.garageNo + "Fragment"}>
<AdvancedMarker
position={markerPosition(point)}
title={markerTitle(point)}
key={point.garageNo}
onClick={() => handleMarkerClick(point)}
ref={(marker) => setMarkerRef(marker, point.garageNo)}
>
<img src={markerIcon(point)} />
</AdvancedMarker>
</React.Fragment>
))}
</React.Fragment>
);
};
CustomMarkers.propTypes = {
points: markerShape.marker,
typeOfApp: PropTypes.string.isRequired,
};
export default CustomMarkers;
but when currentResults
, which are passed as a prop, change as we filter them it causes the following error:
Uncaught Error: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.
Any ideas will be highly appreciated.