3

I have react app using react-google-maps. I want it to have marker fixed at the center of map when user moves the map. But in my case, whenever dragging event happens map is just immediately refreshed.

parent component:

import React, { useState, useEffect } from 'react';
import Map from './Map';
export default function Parent() {
const [mapCenter, setMapCenter] = useState(undefined); 
    const [markerPosition, setMarkerPosition] = useState(undefined);
    useEffect(()=>navigator.geolocation.getCurrentPosition(position => 
        {
            setMapCenter({lat:position.coords.latitude, lng:position.coords.longitude})
            setMarkerPosition({lat:position.coords.latitude, lng:position.coords.longitude})
        }
        ),[])
 return(
        <div>
            { mapCenter && <Map mapCenter={mapCenter} setMapCenter={setMapCenter} markerPosition={markerPosition} setMarkerPosition={setMarkerPosition} />}

        </div>
    )
}

and the map component:

import React from 'react';
import { GoogleMap, Marker, withGoogleMap } from "react-google-maps";

export default function Map(props) {

  let mapRef;
  let markerRef;
  const WrappedMap = withGoogleMap(() =>
    <GoogleMap ref={(ref) => mapRef = ref} center={props.mapCenter} zoom={16} onDrag={()=>{
      const newCenter = mapRef.getCenter().toJSON(); 
      props.setMarkerPosition(newCenter);
      props.setMapCenter(newCenter)
      }}>
      <Marker ref={(ref) => markerRef = ref } position={props.markerPosition} draggable={false}/>
    </GoogleMap>
  );

  return (
    <div style={{ height: "50vh", width: "50vh" }}>
      <WrappedMap
        loadingElement={<div style={{ height: "100%" }} />}
        containerElement={<div id="map" style={{ height: "100%" }} />}
        mapElement={<div style={{ height: "100%" }} />}
      />
    </div>
  )
}

I expected that when user drag map, parent's states get updated and marker moves to the new location but it doesn't work as I expected. What am I missing here?

김민겸
  • 75
  • 2
  • 8

1 Answers1

0

To achieve your use case, in your parent component, you need to use a handleChangeCenter function that will set the newvalue of your center and marker then you will pass an onChange parameter to your child component which calls the handleChangeCenter function.

In your child component, instead of onDrag function of <GoogleMap/> object , you can use the onDragEnd and onDragEnd, you will call a handleChange function that gets the current center coordinate of the map on dragEnd and it will pass the new value to the props of the onChange changing the state of your center and marker.

Here's a sample code and a code snippet below:

parent.js

import React, { useState, useEffect } from 'react';
import Map from './Map';
export default function Parent() {
const [mapCenter, setMapCenter] = useState(undefined); 
    const [markerPosition, setMarkerPosition] = useState(undefined);

    function handleChangeCenter(newValue) {
      setMapCenter(newValue);
      setMarkerPosition(newValue)
    }


    useEffect(()=>navigator.geolocation.getCurrentPosition(position => 
        {
            setMapCenter({lat:position.coords.latitude, lng:position.coords.longitude})
            setMarkerPosition({lat:position.coords.latitude, lng:position.coords.longitude})
        }
        ),[])
 return(
        <div>
            { mapCenter && <Map mapCenter={mapCenter}  markerPosition={markerPosition}  onChange={handleChangeCenter} />}

        </div>
    )
}

Map.js

import React from 'react';
import { GoogleMap, Marker, withGoogleMap } from 'react-google-maps';

export default function Map(props) {
  let mapRef;
  function handleChange() {
    // Here, we invoke the callback with the new value
    const newCenter = mapRef.getCenter().toJSON();
    console.log(newCenter);
    props.onChange(newCenter);
  }

  const WrappedMap = withGoogleMap(() => (
    <GoogleMap
      ref={(ref) => (mapRef = ref)}
      center={props.mapCenter}
      zoom={16}
      onDragEnd={handleChange}
    >
      <Marker position={props.markerPosition} draggable={false} />
    </GoogleMap>
  ));

  return (
    <div style={{ height: '50vh', width: '50vh' }}>
      <WrappedMap
        loadingElement={<div style={{ height: '100%' }} />}
        containerElement={<div id="map" style={{ height: '100%' }} />}
        mapElement={<div style={{ height: '100%' }} />}
      />
    </div>
  );
}
Pagemag
  • 2,779
  • 1
  • 7
  • 17