Skip to content

[Bug] mouse-movement not working when using some controlled props #425

Open

Description

@usefulthink

Description

When controlled props are updated/restricted when handling the cameraChanged events, map can't be dragged anymore.

(source: #423)

Steps to Reproduce

https://codesandbox.io/p/devbox/snowy-dream-hnwmyh?file=%2Fsrc%2Fapp.tsx%3A19%2C1-20%2C1

Environment

  • Library version: 1.1.0
  • Google maps version: 3.57.4 (weekly)
  • Browser and Version: any
  • OS: any

Logs

No response

Activity

  1. shirleyodeng commented on Jul 4, 2024

    @shirleyodeng

    Hi, I am having this exact issue where I can't drag / interact with the map if I have controlled props and update them from the cameraChanged events. I saw this closed similar issue #436 that was created after this issue was opened so is this fixed? 🤔

  2. usefulthink commented on Jul 4, 2024

    @usefulthink
    CollaboratorAuthor

    @shirleyodeng Unfortunately not, and it seems this is going to be very hard to fix (if possible at all), but I am on it.

    In the meantime, can you tell me what you are using the controlled props for? Maybe there are alternative solutions that work for your use-case.

  3. shirleyodeng commented on Jul 4, 2024

    @shirleyodeng

    Thanks for the speedy reply @usefulthink.

    I have a map component which has either one or two markers. If it has two markers, I would it to center the map accordingly on load. You can see that I've used markerOne's coordinates for the center. So I saw that on load, it will trigger a MapCameraChangedEvent so I thought this would returns the center of the map of the two markers and then set the props accordingly. But maybe I'm approaching this incorrectly - is there a better way?

    const [mapCenter, setMapCenter] = useState({ lat: markerOne.lat, lng: markerOne.lng })
    const [mapZoom, setMapZoom] = useState(defaultZoom)
    
      <Map
        center={mapCenter}
        zoom={mapZoom}
        mapId="mapId"
        onCameraChanged={(event) => {
          setMapCenter(event.detail.center)
          setMapZoom(event.detail.zoom)
        }}
      >
        <AdvancedMarker position={{ lat: markerOne.lat, lng: markerOne.lng }} />
        {!!markerTwo && <AdvancedMarker position={{ lat: markerTwo.lat, lng: markerTwo.lng }} /> }
      </Map>
    
  4. usefulthink commented on Jul 4, 2024

    @usefulthink
    CollaboratorAuthor

    Oh, that might actually be a different issue that could be fixable. The details are a bit difficult to explain, but I think I have an Idea whats wrong there, I'll have a look into this.

    What you could try is to use the full CameraState instead of just the zoom and center props, for example:

    const INITIAL_CAMERA_STATE = {
      center: {lat: 0, lng: 0},
      zoom: 5,
      heading: 0,
      tilt: 0
    };
    
    const MapComponent = () => {
      const [cameraState, setCameraState] = useState(INITIAL_CAMERA_STATE);
    
      return (
        <Map {...cameraState} onCameraChanged={(ev) => setCameraState(ev.detail)}></Map>
      );
    };

    If you now want to update the camera-center without touching the zoom (same goes the other way around), you can use the state setter function like this:

    const updateCenter = useCallback(newCenter => {
      setCameraState(prevCameraState => {
        return {...prevCameraState, center: newCenter};
      });
    }, []);

    Another alternative would be to use the defaultBounds prop of the map (if you know the positions of your markers at initialization time), or the imperative API (map.fitBounds() method):

    const map = useMap();
    useEffect(() => {
      if (!map || markerPositions.length === 0) return;
    
      // assuming markerPositions is just a `google.maps.LatLngLiteral[]`
      const bounds = new google.maps.LatLngBounds();
      for (let p of markerPositions) {
        bounds.extend(p);
      }
      map.fitBounds(bounds);
    }, [map, markerPositions]);
  5. shirleyodeng commented on Jul 4, 2024

    @shirleyodeng

    @usefulthink thank you for your suggestions!

    I tried using the full camera state but I came across the same non-draggable issue on the map:

    Screen.Recording.2024-07-04.at.22.34.28.mov

    So I've gone with your latter suggestion and that's worked - thank you again 🙌

  6. JarmoKamux commented on Aug 7, 2024

    @JarmoKamux

    I had this same issue and struggled with it for a couple of days. Using the cameraEventHandler-method did nothing for me and ultimately for me it was solved by changing

    <Map
                className="relative top-0 w-full lg:max-h-full lg:flex-1"
                center={{ lat: 62.898, lng: 27.6782 }}
                zoom={6}
              >
    

    to using

    
    <Map
                className="relative top-0 w-full lg:max-h-full lg:flex-1"
                gestureHandling={'greedy'}
                defaultCenter={{ lat: 62.898, lng: 27.6782 }}
                defaultZoom={6}
              >
    

    So to me it seems that the non-prefixed values are interfering with some of the eventHandler in the library itself.

  7. bdubetink commented on Aug 16, 2024

    @bdubetink

    I know this bug has been describe as "is going to be very hard to fix", but is there an update upon a possible fix ? or a workaround?

    I had a workaround in place where ondrag event and onZoomChanged event I resseted the custom zoom and center position that I had previously set, but using center and zoom props, prevent the infowindows autopan functionnality.

    So I'm in a situation where I can have the autopan on infowindow opening or the ability to zoom and center the map on a location and be able to drag and zoom the map manually after, but not both features.

    That is a dealbreaker for the app we develop and if there is no solution, it would force us to compeltely redo the work.

    Thanks

  8. niranjan404 commented on Aug 19, 2024

    @niranjan404

    I know this bug has been describe as "is going to be very hard to fix", but is there an update upon a possible fix ? or a workaround?

    I had a workaround in place where ondrag event and onZoomChanged event I resseted the custom zoom and center position that I had previously set, but using center and zoom props, prevent the infowindows autopan functionnality.

    So I'm in a situation where I can have the autopan on infowindow opening or the ability to zoom and center the map on a location and be able to drag and zoom the map manually after, but not both features.

    That is a dealbreaker for the app we develop and if there is no solution, it would force us to compeltely redo the work.

    Thanks

    Can you share the fix you made for this one? stuck in this for almost one week.

  9. niranjan404 commented on Aug 19, 2024

    @niranjan404

    All possible solutions mentioned not working for me: @usefulthink Please help fix this, I am using "@vis.gl/react-google-maps": "1.1.0", 😭

    I want the users to be able to see the map by moving inside it using their cursor but not works

            const onZoomChanged = (event: MapCameraChangedEvent) => {
              const { detail: { zoom } } = event || {};
              setState({
                zoom,
              });
            };
          
            const handleCameraChange = (event: MapCameraChangedEvent) => {
              const { detail: { center: { lat, lng } } } = event || {};
              setState({
                defaultBounds: {
                  lat: lat,
                  lng: lng,
                },
                zoom,
              });
            };
           <Map
            mapId='shared-widgets'
            zoom={zoom}
            onZoomChanged={onZoomChanged}
            onCameraChanged={handleCameraChange}
            controlSize={20}
            mapTypeId='hybrid'
            zoomControl={true}
            clickableIcons={false}
            disableDefaultUI={true}
            reuseMaps={true}
            defaultCenter={defaultBounds}
            center={defaultBounds}
            gestureHandling='greedy'
            streetViewControl={false}
            keyboardShortcuts={true}
            className={classes.swMapStyle}
          />
    
  10. bdubetink commented on Aug 19, 2024

    @bdubetink

    I know this bug has been describe as "is going to be very hard to fix", but is there an update upon a possible fix ? or a workaround?
    I had a workaround in place where ondrag event and onZoomChanged event I resseted the custom zoom and center position that I had previously set, but using center and zoom props, prevent the infowindows autopan functionnality.
    So I'm in a situation where I can have the autopan on infowindow opening or the ability to zoom and center the map on a location and be able to drag and zoom the map manually after, but not both features.
    That is a dealbreaker for the app we develop and if there is no solution, it would force us to compeltely redo the work.
    Thanks

    Can you share the fix you made for this one? stuck in this for almost one week.

    • I define the defaultZoom and center props at load with the default position of my map.
    • Then, when a user click on a card linked to a marker, I set the zoom props to the new zoom I want, and I change the state I use for the center props value, to use the new position.
      After those change, if nothing done, I can't move or scroll the map with the mouse anymore.

    What I have done to be able to, is to add those to event to the Map component :

    I set sone states bfore

    /* mapPos is a props of my component */
    const [mapCenterPos, setMapCenterPos] = useState({ lat: mapPos.lat, lng: mapPos.lng });
    const [mapZooming, setMapZooming] = useState(10);
    
    useEffect(() => {
        setMapCenterPos(center);
      }, [center]);
    
      useEffect(() => {
        setMapZooming(mapZoom);
      }, [mapZoom]);
    
    <Map
        ...
        defaultZoom={mapZoom}
        center={mapCenterPos}
        zoom={mapZooming}
        onDrag={() => { resetCenter() }}
        onZoomChanged={() => { resetZoom() }}
    >...</Map>
    

    and in those event, I reset the state I used to set the maps props :

    const resetCenter = () => {
        setMapCenterPos(false);
      }
    
      const resetZoom = () => {
        setMapZooming(false);
      }
    

    Sorry if I can't sahre all my code, it is compose of multiple components in a big project.

    But the fix with the event that I have done, prevent the autopan feature to work as describe here : https://visgl.github.io/react-google-maps/docs/api-reference/components/info-window#infowindow-attached-to-marker

    That the issue I still have and still need to fix ASAP

  11. niranjan404 commented on Aug 19, 2024

    @niranjan404

    I know this bug has been describe as "is going to be very hard to fix", but is there an update upon a possible fix ? or a workaround?
    I had a workaround in place where ondrag event and onZoomChanged event I resseted the custom zoom and center position that I had previously set, but using center and zoom props, prevent the infowindows autopan functionnality.
    So I'm in a situation where I can have the autopan on infowindow opening or the ability to zoom and center the map on a location and be able to drag and zoom the map manually after, but not both features.
    That is a dealbreaker for the app we develop and if there is no solution, it would force us to compeltely redo the work.
    Thanks

    Can you share the fix you made for this one? stuck in this for almost one week.

    • I define the defaultZoom and center props at load with the default position of my map.
    • Then, when a user click on a card linked to a marker, I set the zoom props to the new zoom I want, and I change the state I use for the center props value, to use the new position.
      After those change, if nothing done, I can't move or scroll the map with the mouse anymore.

    What I have done to be able to, is to add those to event to the Map component :

    I set sone states bfore

    /* mapPos is a props of my component */
    const [mapCenterPos, setMapCenterPos] = useState({ lat: mapPos.lat, lng: mapPos.lng });
    const [mapZooming, setMapZooming] = useState(10);
    
    useEffect(() => {
        setMapCenterPos(center);
      }, [center]);
    
      useEffect(() => {
        setMapZooming(mapZoom);
      }, [mapZoom]);
    
    <Map
        ...
        defaultZoom={mapZoom}
        center={mapCenterPos}
        zoom={mapZooming}
        onDrag={() => { resetCenter() }}
        onZoomChanged={() => { resetZoom() }}
    >...</Map>
    

    and in those event, I reset the state I used to set the maps props :

    const resetCenter = () => {
        setMapCenterPos(false);
      }
    
      const resetZoom = () => {
        setMapZooming(false);
      }
    

    Sorry if I can't sahre all my code, it is compose of multiple components in a big project.

    But the fix with the event that I have done, prevent the autopan feature to work as describe here : https://visgl.github.io/react-google-maps/docs/api-reference/components/info-window#infowindow-attached-to-marker

    That the issue I still have and still need to fix ASAP

    Oh man you are a saviour 🫰

  12. angelsvirkov commented on Aug 12, 2025

    @angelsvirkov
    Contributor

    I know this bug has been describe as "is going to be very hard to fix", but is there an update upon a possible fix ? or a workaround?
    I had a workaround in place where ondrag event and onZoomChanged event I resseted the custom zoom and center position that I had previously set, but using center and zoom props, prevent the infowindows autopan functionnality.
    So I'm in a situation where I can have the autopan on infowindow opening or the ability to zoom and center the map on a location and be able to drag and zoom the map manually after, but not both features.
    That is a dealbreaker for the app we develop and if there is no solution, it would force us to compeltely redo the work.
    Thanks

    Can you share the fix you made for this one? stuck in this for almost one week.

    • I define the defaultZoom and center props at load with the default position of my map.
    • Then, when a user click on a card linked to a marker, I set the zoom props to the new zoom I want, and I change the state I use for the center props value, to use the new position.
      After those change, if nothing done, I can't move or scroll the map with the mouse anymore.

    What I have done to be able to, is to add those to event to the Map component :

    I set sone states bfore

    /* mapPos is a props of my component */
    const [mapCenterPos, setMapCenterPos] = useState({ lat: mapPos.lat, lng: mapPos.lng });
    const [mapZooming, setMapZooming] = useState(10);
    
    useEffect(() => {
        setMapCenterPos(center);
      }, [center]);
    
      useEffect(() => {
        setMapZooming(mapZoom);
      }, [mapZoom]);
    
    <Map
        ...
        defaultZoom={mapZoom}
        center={mapCenterPos}
        zoom={mapZooming}
        onDrag={() => { resetCenter() }}
        onZoomChanged={() => { resetZoom() }}
    >...</Map>
    

    and in those event, I reset the state I used to set the maps props :

    const resetCenter = () => {
        setMapCenterPos(false);
      }
    
      const resetZoom = () => {
        setMapZooming(false);
      }
    

    Sorry if I can't sahre all my code, it is compose of multiple components in a big project.

    But the fix with the event that I have done, prevent the autopan feature to work as describe here : https://visgl.github.io/react-google-maps/docs/api-reference/components/info-window#infowindow-attached-to-marker

    That the issue I still have and still need to fix ASAP

    Thanks for the solution, @bdubetink , I managed to simplify it and it works for my case even with auto-panning of <InfoWindow>. In my case, though, I don't care about the zoom, but it works with it, as well. I think the only thing that matters for the solution is that the moment some interaction happens within the map itself, then we need to make the GoogleMap.center prop null so that we restore it to uncontrolled behaviour.

    Here is my approach:

        // Start mapCenter in controlled state for the initial render
        const [mapCenter, setMapCenter] = useState({lat: 30, lng: 150});
    
        const makeMapCenterUncontrolled = useCallback(() => {
          setMapCenter(null);
        }, []);
    
       return (
         <GoogleMap
            center={props.mapState.center}
            onDrag={props.mapState.makeMapCenterUncontrolled}
            onZoomChanged={props.mapState.makeMapCenterUncontrolled}
         />
    
        ...
        <button onClick={() => {setMapCenter({...})}}>Change Center</button>
       )

    An alternative solution that might not be available for all business cases involves using the imperative way of controlling the map directly via the classic JS API.

         <GoogleMap
            onIdle={(event) => { /* store the map reference from the event inside a useRef */ } }
         />
    
        // `map.panTo` - provide a very smooth transitioning
        <button onClick={() => { mapRef.panTo(someLocatio) }} />
  13. mvanhorn commented on Oct 28, 2026

    @mvanhorn
    Contributor

    After applying controlled camera props, the tracked camera state was not updated until the map emitted its change event. A render occurring before that event could therefore reapply the same camera values repeatedly, interfering with interaction.

    The camera hook now updates its tracked state immediately after calling moveCamera, including renders that occur before the map event arrives. A regression test verifies that unchanged controlled camera props do not trigger repeated moveCamera calls.

    #1108

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions