react-google-maps-api
react-google-maps-api copied to clipboard
MarkerClusterer does not work in Strictmode (React v18+)
Please provide an explanation of the issue
When using MarkerClusterer in Strict Mode - no markers or clusters are rendered. Since Strict mode mounts & unmounts twice I would imagine that is causing an issue.
Your Environment
os: windows
node --version: 16.14.0
react version: 18.0.0
@react-google-maps/api version: 2.12.0
How does it behave?
Nothing is displayed on the map in strict mode.
How should it behave correctly?
Markers & clusters should appear in strict mode.
Basic implementation of incorrect behavior in codesandbox.com
With StrictMode: https://codesandbox.io/s/rgma-sm-k9suxt?file=/src/App.tsx Without StrictMode: https://codesandbox.io/s/rgma-sm-forked-00ipzt?file=/src/App.tsx
Same issue here, i was driving myself crazy why the clustering was not working properly.
The documentation example is not rendering properly also.
Let me know if there is any way we can help, trying to find a 'good' solution meanwhile.
Thanks @ReeceTrolley-HRS
use MarkerClustererF anf MarkerF components instead
use MarkerClustererF anf MarkerF components instead
Tried using markerF previously and it didnt show up, am i missing something?
use MarkerClustererF anf MarkerF components instead
There's no such thing as MarkerClustererF (unless I'm missing something in the docs - but you can't import it from the package at least).
docs are outdated, due to broken build. look at changelog.md
Sorry, I had no time to implement MarkerClustererF. Your PR is welcome. Please look at source files for examples of F components.
Sorry, I had no time to implement MarkerClustererF. Your PR is welcome. Please look at source files for examples of F components.
can you link it? I can't find the file. thanks
@toppyc4 @ReeceTrolley-HRS @manuelc2209 Released 2.15.0 with MarkerClustererF component. Please test.
#3129 For info on what has been changed
@JustFly1984 @Michaelkire can you provide some example? I tried to use it but got error:
Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports. and here is what return form my Map file:
return (
<div className='w-full h-full'>
{drawingMap ? (
<DrawingMap coordinates={coordinates} />
) : (
<GoogleMap
zoom={zoomLv}
onZoomChanged={(e) => {
if (map === null) {
return
}
if (map.zoom !== zoomLv) {
setZoomLv(e)
}
}}
center={coordinates}
mapContainerClassName='w-full h-[92vh]'
options={options}
onLoad={onLoad}
>
<MarkerClustererF>
{(clusterer) => {
posts?.map((post, i) => {
const markerLetter = String.fromCharCode(
"A".charCodeAt(0) + (i % 26)
)
// console.log("post", post)
return (
<MarkerF
position={post.address.coordinate}
icon={
iconType(post.typeOfService)
// `/img/alphabet-markers/marker_green${markerLetter}.png`
}
key={
post.address.coordinate.lat + post.address.coordinate.lng
}
className='abosolute z-1 cursor-pointer'
onClick={() => handleClick(post.address.coordinate, i)}
clusterer={clusterer}
/>
)
})
}}
</MarkerClustererF>
</GoogleMap>
)}
</div>
)
sorry for my noob
@JustFly1984 @Michaelkire can you provide some example? I tried to use it but got error:
Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports. and here is what return form my Map file:
return ( <div className='w-full h-full'> {drawingMap ? ( <DrawingMap coordinates={coordinates} /> ) : ( <GoogleMap zoom={zoomLv} onZoomChanged={(e) => { if (map === null) { return } if (map.zoom !== zoomLv) { setZoomLv(e) } }} center={coordinates} mapContainerClassName='w-full h-[92vh]' options={options} onLoad={onLoad} > <MarkerClustererF> {(clusterer) => { posts?.map((post, i) => { const markerLetter = String.fromCharCode( "A".charCodeAt(0) + (i % 26) ) // console.log("post", post) return ( <MarkerF position={post.address.coordinate} icon={ iconType(post.typeOfService) // `/img/alphabet-markers/marker_green${markerLetter}.png` } key={ post.address.coordinate.lat + post.address.coordinate.lng } className='abosolute z-1 cursor-pointer' onClick={() => handleClick(post.address.coordinate, i)} clusterer={clusterer} /> ) }) }} </MarkerClustererF> </GoogleMap> )} </div> )sorry for my noob
It seems like React 18 is not keen on having a function returning multiple JSX elements as {children}. I ran into issues myself.
I got to making the ClustererF and MarkerF working in React 17 and haven't had time to progress it further. It also seems now that updates to the underlying google api has changed, which broke some stuff. We might need to rethink the components a bit to take in the markers as a prop instead.
Edit: For yours i just realize that you never return the posts.map.
@Michaelkire yep I forgot to return, haha. Thanks for your clarification.
I can close an issue due to MarkerClustererF implemented
So, I am having the same problem, the MarkerClustererF is currently not working or I am using it in the wrong way? The map appears, but without any clusters.
<GoogleMap
zoom={zoom}
center={center}
mapContainerStyle={{ width: "100%", height: "100%" }}
>
<MarkerClustererF>
{(clusterer) => {
return (
<Fragment>
{locations.map((location) => {
return (
<MarkerF
key={createKey(location)}
position={location}
clusterer={clusterer}
/>
);
})}
</Fragment>
);
}}
</MarkerClustererF>
</GoogleMap>
function createKey(location: { lat: number; lng: number }) {
return location.lat + location.lng;
}
Hi! Did you happen to resolve this problem somehow? Im having the same issue, neither MarkerClusterer or MarkerClustererF work in strictMode
It didn't work for me as well.
MarkerClustererF fixed my issue but not from first try
So it will work if you will render MarkerClustererF at the time when you have data for it like this:
{props.data?.length > 0 && <MarkerClustererF ... />
I'm having the same issue
@maxizhukov this fixed this issue for me as well. Thanks! Needed the extra conditional render of <MarkerClusterF> once the data is loaded.
Answer from @maxizhukov helped! Also I had wrong return statements in clusterer so expample by @RafaelStudartDiPiero helped also
I'm still having problems with this. See anything obvious? Map renders and centers, but no markers. If I remove the MarkerClusterer, they render.
function makeMarkersFromFilteredLocations(clusterer) {
return locationList.reduce((accumulator, l) => {
if (selectedMarkerFilterList.includes(l.type)) {
accumulator.push(
<MarkerF
key={l.id}
className="eventMarker"
map={map}
position={{ lat: l.latitude, lng: l.longitude }}
label={l.description}
title={l.description}
icon={{
url: makeMarkerIcon(l.type),
labelOrigin: new window.google.maps.Point(15, 40),
}}
options={{
opacity: 0.3,
}}
clusterer={clusterer}
onClick={onEventMarkerClick}
/>
);
}
return accumulator;
}, []);
}
return (
<GoogleMap
key="map"
onLoad={onLoad}
center={currentPosition}
zoom={DefaultMapZoom}
mapContainerClassName="EventMapGoogleContainer"
mapContainerStyle={{ width: "100%", height: "100%" }}
options={{
zoomControl: true,
streetViewControl: false,
mapTypeControl: true,
fullScreenControl: true,
}}
>
{locationList && (
<MarkerClustererF>
{(clusterer) => {
return (
<>
{makeMarkersFromFilteredLocations(clusterer)}
</>
);
}}
</MarkerClustererF>
)}
</GoogleMap>
);
};
I'm still having problems with this. See anything obvious? Map renders and centers, but no markers. If I remove the MarkerClusterer, they render.
function makeMarkersFromFilteredLocations(clusterer) { return locationList.reduce((accumulator, l) => { if (selectedMarkerFilterList.includes(l.type)) { accumulator.push( <MarkerF key={l.id} className="eventMarker" map={map} position={{ lat: l.latitude, lng: l.longitude }} label={l.description} title={l.description} icon={{ url: makeMarkerIcon(l.type), labelOrigin: new window.google.maps.Point(15, 40), }} options={{ opacity: 0.3, }} clusterer={clusterer} onClick={onEventMarkerClick} /> ); } return accumulator; }, []); }return ( <GoogleMap key="map" onLoad={onLoad} center={currentPosition} zoom={DefaultMapZoom} mapContainerClassName="EventMapGoogleContainer" mapContainerStyle={{ width: "100%", height: "100%" }} options={{ zoomControl: true, streetViewControl: false, mapTypeControl: true, fullScreenControl: true, }} > {locationList && ( <MarkerClustererF> {(clusterer) => { return ( <> {makeMarkersFromFilteredLocations(clusterer)} </> ); }} </MarkerClustererF> )} </GoogleMap> ); };
Place this into a code sandbox so we can debug & find the reason please.
Any ideas on the above? It's still happening for me. @manuelc2209 have you managed to fix it?
Any ideas on the above? It's still happening for me. @manuelc2209 have you managed to fix it?
Ive requested a sandbox to the author w/ any reply as you can see on the thread and didnt dig any further because i wasnt facing this issue myself and wanted to help ^^
Any ideas on the above? It's still happening for me. @manuelc2209 have you managed to fix it?
If you're still facing issues I'd recommend creating your own issue with a new sandbox and referencing this issue since this one has been closed. Personally I no longer had a need for the MarkerClustererF by the time the new component was implemented so I haven't tested it.
For the record, I was facing the same issue with Marker / MarkerCluster. Not only switching to the functional version of those is needed - MarkerF and MarkerClusterF - but DrawingManagerF should also be used instead of DrawingManager.