tomchentw / react-google-maps

React.js Google Maps integration component
https://tomchentw.github.io/react-google-maps/
MIT License
4.62k stars 939 forks source link

Google map ref #978

Open viveksrivastawa opened 5 years ago

viveksrivastawa commented 5 years ago

Hi All,

I am using 6.3.0 version and want to get map reference using below code but unable to get map ref.

const AsyncGettingStartedExampleGoogleMap = withScriptjs( withGoogleMap( props => ( <GoogleMap mapElement={ <div style={{ height: '100%' }} />

                    } googleMapURL="https://maps.googleapis.com/maps/api/js?key=MYKEY&v=3.exp" loadingElement={
                         <div style={{ height: '100%' }} />

                </div>
                }
                    containerElement={
                          <div style={{ height: '100%' }} />
                }
                 ref={googleMap => {
                        if (!googleMap) {
                            return;
                        }
                      console.log(googleMap);
                    }}

                </GoogleMap> 
                )
              )
            )

I am getting this "__SECRET_MAP_DO_NOT_USE_OR_YOU_WILL_BE_FIRED" as a map context , please let me know how I can get real map ref, I need map ref for marker click and set map on center and other feature like display traffic and route.

beavcast commented 5 years ago

This from the docs can be useful:

const MapWithControlledZoom = compose(
  withProps({
    googleMapURL: "https://maps.googleapis.com/maps/api/js?key=AIzaSyC4R6AN7SmujjPUIGKdyao2Kqitzr1kiRg&v=3.exp&libraries=geometry,drawing,places",
    loadingElement: <div style={{ height: `100%` }} />,
    containerElement: <div style={{ height: `400px` }} />,
    mapElement: <div style={{ height: `100%` }} />,
  }),
  withState('zoom', 'onZoomChange', 8),
  withHandlers(() => {
    const refs = {
      map: undefined,
    }

    return {
      onMapMounted: () => ref => {
        refs.map = ref
      },
      onZoomChanged: ({ onZoomChange }) => () => {
        onZoomChange(refs.map.getZoom())
      }
    }
  }),
  withScriptjs,
  withGoogleMap
)(props =>
  <GoogleMap
    defaultCenter={{ lat: -34.397, lng: 150.644 }}
    zoom={props.zoom}
    ref={props.onMapMounted}
    onZoomChanged={props.onZoomChanged}
  >
    <Marker
      position={{ lat: -34.397, lng: 150.644 }}
      onClick={props.onToggleOpen}
    >
      <InfoWindow onCloseClick={props.onToggleOpen}>
        <div>
          <FaAnchor />
          {" "}
          Controlled zoom: {props.zoom}
        </div>
      </InfoWindow>
    </Marker>
  </GoogleMap>
);

Take a look at " ref={props.onMapMounted}" and "onMapMounted".

rflmyk commented 5 years ago

Cool but show for us as you use this component, him should seem like that:

let mapsRef = React.createRef();
<MapWithControlledZoom ... onMapMounted={ mapsRef } />
JustFly1984 commented 5 years ago

@viveksrivastawa @beavcast @rflmyk Please take a look at @react-google-maps/api We have rebuild this API to support new React.js 16.8. We had rewritten it to TypeSript, and implified API. Also we have a ton of examples and documentation. You get autocomplete in VScode for free. https://github.com/JustFly1984/react-google-maps-api/tree/master/packages/react-google-maps-api

TroyWolf commented 5 years ago

After several hours simply trying to get a map reference, and yes, unsuccessfully trying the tricks in this thread and elsewhere, I have had to say "screw it" and just use the reference that is easily available despite being named __SECRET_MAP_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.

I'm using a functional component and the new React useState() hook:

const [mapRef, setMapRef] = useState(null)

Then in the component, I include this prop:

ref={ref => setMapRef(ref)}

This allows me to later (in event handlers, etc) to access the "raw" google map object:

const map = mapRef.context.__SECRET_MAP_DO_NOT_USE_OR_YOU_WILL_BE_FIRED

If you don't want me to use context.__SECRET_MAP_DO_NOT_USE_OR_YOU_WILL_BE_FIRED then how about a simple getMap() method, please?!

:coffee:

molimauro commented 5 years ago

Try typing "google" in your browser console while developing. If it returns a map object, you can use the global variable "google" in your code in order to obtain the google map object that your're searching for. I'm using this library for a project and this trick works.

JustFly1984 commented 5 years ago

guys, try our new lib @react-google-maps/api

TroyWolf commented 5 years ago

@molimauro , close but fail for me. I do see some folks report this works for them, so not sure what's different for me, but the google object contains the classes but not my map instance. Screenshot from 2019-06-21 07-22-46 Don't be fooled by google.maps.Map as that is just the Map class--not my map instance. I did not find any methods that would allow me to get my instance either. Ideas?

@JustFly1984 I WANT TO! I saw your comment about your newer version in another thread and checked it out. I installed yesterday and rewrote my component to use it--VERY easy, less code, and easy to get a map reference. However, I ran into some issues I did not know how to handle.

First was every time my data reloaded (graphql polling every 15 seconds), the map would recenter to the original center setting. The user's modified zoom would survive, but not position. So if the user pans and zooms, after about 15 seconds, the map recenters. react-google-maps does not do this.

Second issue was several things just didn't work as described in the very clear documentation. For example, if I tried to use the useGoogleMap() hook and other hooks in the package, things fail with:

Error: invariant requires an error message argument

I am using React 16.8.6.

Googling for that error resulted in VERY few hits---like a Google search unicorn. I'm not using Typescript and am admittedly naive about Typescript. Does this make my project not fully compatible with your package?

Thanks! :coffee:

molimauro commented 5 years ago

@viveksrivastawa @TroyWolf may I ask you why you need the map instance? Is there something that you can't do with the available library functions?

TroyWolf commented 5 years ago

@molimauro Something I'd consider very normal for a map application: Upon Marker click, I want to do things like:

  1. Center map on the Marker map.setCenter() or map.panTo()
  2. Zoom in a few levels map.setZoom()
  3. Pop a small modal with info about the item

In my Marker onClick handler, how does the package intend for me to perform map.setZoom(11)?

molimauro commented 5 years ago

@TroyWolf I currently do all the things you've mentioned in this way:

<GoogleMap
    center={props.center} // center instead of defaultCenter
    zoom={props.zoom}
    ref={props.onMapMounted}
    onZoomChanged={props.onZoomChanged}
    ...
  >

where props.center is an object = {lat: -24.397, lng: 160.644}. If you change this props upon the marker click the map will be recentered. The same for props.zoom

<Marker
      position={{ lat: -34.397, lng: 150.644 }}
      onClick={ () => props.changeZoomAndCenterAndDoOtherStuff(-34.397, 150.644, 11)}
    >

And in the map parent component define the function:

changeZoomAndCenterAndDoOtherStuff(lat, lng, zoom) {
     this.setState({
      center: {lat: lat, lng: lng}
      zoom: zoom
    });
} 

Of course this is only an example, hope it helps and let me know if this works for you.

TroyWolf commented 5 years ago

@molimauro, that does help. Thank you! @JustFly1984 , it also explains my center issue with your package. It's the difference between center and defaultCenter. Fixed by maintaining a state variable for the center position, changing it in my Marker onClick handler, and using it here:

<GoogleMap center={center} ...other props />

I was hoping to get the panning animation effect when changing center. I think it's what map.panTo() does, but not sure how to accomplish that with either of these react-google-maps packages.

molimauro commented 5 years ago

Glad it helped. The effect of panning, in my case, happens when the actual center of the map and the center you're going to set are close, otherwise no effect is obtained (this happens also on Google Maps website when you search for a close location and for a far one).

JustFly1984 commented 5 years ago

‘Error: invariant requires an error message argument’ Means that you forgot to include correct ‘libraries’ prop to LoadScript

TroyWolf commented 5 years ago

@JustFly1984 , quick FYI -- I'm using @react-google-maps/api now. Thanks for being so responsive! :coffee:

THANKS to @molimauro, too!

Kolimar commented 4 years ago

@react-google-maps/api did not work for me. It has many bugs, including one in which using "directionsService" makes a lot of requests. I tried to handle this error in many ways but I still think that tomchentw's library with all its problems still better for production.

JustFly1984 commented 4 years ago

@Kolimar You need to handle directionService requests using debounce pattern. People has different business requirements, and our app is plain layer on top of google maps api. You have all the freedom and usability.

If you think there is issues in component's design, file an issue in our repository, or even better - make a PR.

You are welcome.

vipulm124 commented 4 years ago

@TroyWolf I currently do all the things you've mentioned in this way:

<GoogleMap
    center={props.center} // center instead of defaultCenter
    zoom={props.zoom}
    ref={props.onMapMounted}
    onZoomChanged={props.onZoomChanged}
    ...
  >

where props.center is an object = {lat: -24.397, lng: 160.644}. If you change this props upon the marker click the map will be recentered. The same for props.zoom

<Marker
      position={{ lat: -34.397, lng: 150.644 }}
      onClick={ () => props.changeZoomAndCenterAndDoOtherStuff(-34.397, 150.644, 11)}
    >

And in the map parent component define the function:

changeZoomAndCenterAndDoOtherStuff(lat, lng, zoom) {
     this.setState({
      center: {lat: lat, lng: lng}
      zoom: zoom
    });
} 

Of course this is only an example, hope it helps and let me know if this works for you.

I know it's an old thread but I came across it as I am facing issue in implementing a simple functionality Trying to move the zoom controls to top-left from the default position of bottom-right. Unable to do it as 'google' is not defined. Do you have any idea?

TroyWolf commented 4 years ago

@vipulm124, Unfortunately, I have not been using any of these Google Map related packages for almost a year now--I moved off the project where I was using this heavily. I no longer have access to that code to research this for you.

However, I can tell you this from memory.... I switched to using react-google-maps/api https://react-google-maps-api-docs.netlify.app/

The secret, as I recall was to use their useLoadScript() helper. It resulted in window.google being available.

molimauro commented 4 years ago

Hi @vipulm124, try this:

<GoogleMap
    center={props.center} // center instead of defaultCenter
    zoom={props.zoom}
    ref={props.onMapMounted}
    onZoomChanged={props.onZoomChanged}
    defaultOptions={{zoomControlOptions: {position: 1}}} // 1 === window.google.maps.ControlPosition.TOP_LEFT 
    ...
  >

Let me know if this works!

vipulm124 commented 4 years ago

defaultOptions={{zoomControlOptions: {position: 1}}}

Hi @molimauro

I think I forgot to mention, but I am using react-google-maps/api. Although, your idea worked just by updated it as options={{zoomControlOptions: {position: 1}}}

Still, I will keep searching the way to use 'google' keyword in react-google-maps/api package

Thanks alot for your help

vipulm124 commented 4 years ago

@vipulm124, Unfortunately, I have not been using any of these Google Map related packages for almost a year now--I moved off the project where I was using this heavily. I no longer have access to that code to research this for you.

However, I can tell you this from memory.... I switched to using react-google-maps/api https://react-google-maps-api-docs.netlify.app/

The secret, as I recall was to use their useLoadScript() helper. It resulted in window.google being available.

@TroyWolf Sorry I forgot to mention, I am using react-google-maps/api. Unable to use 'google.maps' there itself.

Let me know if you have any idea about this

Thanks in advance

molimauro commented 4 years ago

Sorry for the question but also the variable window.google is undefined?

vipulm124 commented 4 years ago

Sorry for the question but also the variable window.google is undefined?

@molimauro - Yes, even the window.google is giving error that 'google is undefined

Wugka commented 3 years ago

@TroyWolf So Is it safe to use this "__ SECRET_MAP_DO_NOT_USE_OR_YOU_WILL_BE_FIRED" sir ? because it's working lol