react-google-maps-api icon indicating copy to clipboard operation
react-google-maps-api copied to clipboard

MarkerClusterer does not work in Strictmode (React v18+)

Open ReeceTrolley-HRS opened this issue 3 years ago • 6 comments

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

ReeceTrolley-HRS avatar Jul 17 '22 16:07 ReeceTrolley-HRS

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

manuelc2209 avatar Jul 28 '22 00:07 manuelc2209

use MarkerClustererF anf MarkerF components instead

JustFly1984 avatar Aug 03 '22 16:08 JustFly1984

use MarkerClustererF anf MarkerF components instead

Tried using markerF previously and it didnt show up, am i missing something?

manuelc2209 avatar Aug 03 '22 20:08 manuelc2209

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).

ReeceTrolley-HRS avatar Aug 04 '22 07:08 ReeceTrolley-HRS

docs are outdated, due to broken build. look at changelog.md

JustFly1984 avatar Aug 23 '22 21:08 JustFly1984

Sorry, I had no time to implement MarkerClustererF. Your PR is welcome. Please look at source files for examples of F components.

JustFly1984 avatar Aug 23 '22 21:08 JustFly1984

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 avatar Oct 25 '22 05:10 toppyc4

@toppyc4 @ReeceTrolley-HRS @manuelc2209 Released 2.15.0 with MarkerClustererF component. Please test.

JustFly1984 avatar Nov 06 '22 06:11 JustFly1984

#3129 For info on what has been changed

Michaelkire avatar Nov 06 '22 09:11 Michaelkire

@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

toppyc4 avatar Nov 12 '22 12:11 toppyc4

@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 avatar Nov 12 '22 12:11 Michaelkire

@Michaelkire yep I forgot to return, haha. Thanks for your clarification.

toppyc4 avatar Nov 13 '22 02:11 toppyc4

I can close an issue due to MarkerClustererF implemented

JustFly1984 avatar Nov 15 '22 06:11 JustFly1984

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;
}

RafaelStudartDiPiero avatar Nov 17 '22 01:11 RafaelStudartDiPiero

Hi! Did you happen to resolve this problem somehow? Im having the same issue, neither MarkerClusterer or MarkerClustererF work in strictMode

Tillytaly avatar Nov 26 '22 11:11 Tillytaly

It didn't work for me as well.

matt-ribbiot avatar Dec 06 '22 01:12 matt-ribbiot

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 ... />

maxizhukov avatar Dec 06 '22 22:12 maxizhukov

I'm having the same issue

YairoR avatar Jan 14 '23 21:01 YairoR

@maxizhukov this fixed this issue for me as well. Thanks! Needed the extra conditional render of <MarkerClusterF> once the data is loaded.

wcedmisten-reify avatar Jan 23 '23 17:01 wcedmisten-reify

Answer from @maxizhukov helped! Also I had wrong return statements in clusterer so expample by @RafaelStudartDiPiero helped also

Resetnak avatar Apr 16 '23 14:04 Resetnak

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>
      );
   };

jnorvell avatar Jun 07 '23 22:06 jnorvell

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.

manuelc2209 avatar Jun 09 '23 21:06 manuelc2209

Any ideas on the above? It's still happening for me. @manuelc2209 have you managed to fix it?

gerasimosgakis avatar Jul 05 '23 14:07 gerasimosgakis

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 ^^

manuelc2209 avatar Jul 05 '23 14:07 manuelc2209

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.

ReeceTrolley-HRS avatar Jul 05 '23 14:07 ReeceTrolley-HRS

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.

yamafaktory avatar Aug 02 '23 12:08 yamafaktory