I am using react-google-maps to show the location of the user after fetching her co-ordinates using ReactJS. But, when I move marker from the original position, the initial marker stays there, so two markers are created. I don't know how to fix this.
I want that whatever happens, the Map Marker remains at center, also when the user drags OR zoom in/out of the marker, the marker remains at center, so that the user's location is always at the center of the map. In this way, the user will be able to update her location. As per your example, when I drag, the marker stays fixed in it's location This component was designed so that the user can set her location, with a little bit of tweaking the Marker's position, in case the marker is a little bit off Any Help will be appreciated:
App.js
import React from "react";
import WrappedMap from "./Map";
import "./styles.css";
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
location: "",
place: ""
};
}
handleLocation = (location) => {
this.setState({ location: location });
};
handlePlace = (place) => {
this.setState({ place: place });
};
render() {
return (
<div className="App">
<WrappedMap
googleMapURL={`https://maps.googleapis.com/maps/api/js?key=`}
loadingElement={<div style={{ height: `100%` }} />}
containerElement={
<div
style={{
height: `50%`,
width: "95%",
position: "absolute",
marginTop: "25%"
}}
/>
}
mapElement={<div style={{ height: `100%` }} />}
location={this.state.location}
handleLocation={this.handleLocation}
changeState={this.changeState}
place={this.state.place}
handlePlace={this.handlePlace}
handleUseGPS={this.handleUseGPS}
/>
</div>
);
}
}
Map.js
import React, { useRef, useState, useEffect } from "react";
import Geocode from "react-geocode";
import Button from "@material-ui/core/Button";
import {
GoogleMap,
withScriptjs,
withGoogleMap,
Marker
} from "react-google-maps";
// import "./Sign.css";
function Map({
location,
handleLocation,
changeState,
place,
handlePlace,
handleUseGPS
}) {
const [center, setCenter] = useState(location);
const [showMap, setShowMap] = useState(false);
const refMap = useRef(null);
var options = {
enableHighAccuracy: true,
timeout: 10000,
maximumAge: 30000
};
function success(pos) {
var crd = pos.coords;
console.log(crd);
console.log("Your current position is:");
console.log(`Latitude : ${crd.latitude}`);
console.log(`Longitude: ${crd.longitude}`);
console.log(`More or less ${crd.accuracy} meters.`);
const loc = {
lat: crd.latitude,
lng: crd.longitude
};
handleLocation(loc);
getAndChangeAddress(loc);
setCenter(loc);
setShowMap(true);
}
function error(err) {
if (!navigator.geolocation) {
console.log("Geolocation is not supported by your browser");
} else {
console.log("loading");
}
let typeErr = err.code;
console.log(`Code: ${typeErr}`);
switch (typeErr) {
case 1:
console.log("User has not given permissions");
break;
case 2:
console.log(
"The acquisition of the geolocation failed because at least one internal source of position returned an internal error."
);
break;
case 3:
console.log("Timeout reached before obtaining information");
break;
default:
break;
}
console.warn(`ERROR(${err.code}): ${err.message}`);
handlePlace("");
handleLocation({});
// handleUseGPS(true);
// changeState(7);
}
const handleBoundsChanged = () => {
const mapCenter = refMap.current.getCenter(); //get map center
setCenter(mapCenter);
};
useEffect(() => {
navigator.geolocation.getCurrentPosition(success, error, options);
}, []);
const handleDragEnd = () => {
const newCenter = refMap.current.getCenter();
const newLocation = {
lat: newCenter.lat(),
lng: newCenter.lng()
};
handleLocation(newLocation);
getAndChangeAddress(newLocation);
};
const returnToMenu = () => {
// changeState(4);
};
const getAndChangeAddress = (loc) => {
const lat = loc.lat.toString();
const lng = loc.lng.toString();
console.log(typeof lat);
console.log(`From getAddress() function => lat: ${lat}, lng: ${lng}`);
Geocode.fromLatLng(lat, lng).then(
(response) => {
const address = response.results[0].formatted_address;
console.log(`Formatted address: ${address}`);
handlePlace(address);
},
(error) => {
console.error(error);
console.log("Error occuredd in getting address");
}
);
};
return (
<>
<div className="sign-in-form">
{showMap && (
<GoogleMap
ref={refMap}
defaultZoom={15}
defaultCenter={center}
onBoundsChanged={handleBoundsChanged}
onDragEnd={handleDragEnd}
>
<Marker
// defaultPlace={center}
position={center}
// ref={refMap}
// defaultPosition={center}
// onDrag={handleBoundsChanged}
// onDragEnd={handleDragEnd}
/>
</GoogleMap>
)}
{location.lat !== "" && (
<>
<hr />
<div style={{ margin: "1em" }}>{place}</div>
<hr />
</>
)}
<Button
className="otp-button"
onClick={returnToMenu}
fullWidth
variant="contained"
>
SAVE LOCATION
</Button>
</div>
</>
);
}
export default withScriptjs(withGoogleMap(Map));
Also See: CodeSandbox Link
google-map-react is a component written over a small set of the Google Maps API. It allows you to render any React component on the Google Map. It is fully isomorphic and can render on a server. Additionally, it can render map components in the browser even if the Google Maps API is not loaded.
I believe what is happening here is you have set your marker position to center
so whenever you drag, a second marker will be generated.
Instead, the react-google-maps docs show an option where you can hard code the latitude and longitude to the marker. Benefits: no duplicate marker. Con: If the user enters a different address that requires the marker to move, you'll need to write an update function.
Change these lines and your issue should be resolved:
function Map({
location,
handleLocation,
changeState,
place,
handlePlace,
handleUseGPS
}) {
const [center, setCenter] = useState(location);
const [showMap, setShowMap] = useState(false);
const [mylat, setLat] = useState(0); {/* <------ add this hook */}
const [mylong, setLong] = useState(0); {/* <------ and this hook */}
const refMap = useRef(null);
...
function success(pos) {
var crd = pos.coords;
console.log(crd);
console.log("Your current position is:");
console.log(`Latitude : ${crd.latitude}`);
console.log(`Longitude: ${crd.longitude}`);
console.log(`More or less ${crd.accuracy} meters.`);
setLat(crd.latitude); {/* <------ set state here*/}
setLong(crd.longitude); {/* <------ set state here*/}
const loc = {
lat: crd.latitude,
lng: crd.longitude
};
handleLocation(loc);
getAndChangeAddress(loc);
setCenter(loc);
setShowMap(true);
}
<GoogleMap
ref={refMap}
defaultZoom={15}
defaultCenter={center}
onBoundsChanged={handleBoundsChanged}
onDragEnd={handleDragEnd}
>
<Marker
// defaultPlace={center}
position={{ lat: mylat, lng: mylong}} {/* <----- lat and long here */}
// ref={refMap}
// defaultPosition={center}
// onDrag={handleBoundsChanged}
// onDragEnd={handleDragEnd}
/>
</GoogleMap>
OP responded with a clarification that <Marker />
should actually move with the center of the screen, and the issue is that there is a duplicate.
After much debugging, I found the error is due to the way the element is rendered. Change:
import React, { Component } from 'react';
import { render } from 'react-dom';
import App from "./App";
render(<App />, document.getElementById('root'));
And your issue is resolved. This also works:
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
const rootElement = document.getElementById("root");
ReactDOM.render(
<App />, {/* <-------- remove <StrictMode /> */}
rootElement
);
There is a warning in your console about strict mode, and turning it off seems to fix your issue and is the root of the reason why your GoogleMap
component was not working as intended:
Warning: Legacy context API has been detected within a strict-mode tree. The old API will be supported in all 16.x releases, but applications using it >should migrate to the new version. Please update the following components: GoogleMap, Marker Learn more about this warning here: ... in StrictMode (at src/index.js:8)
I also found another StackOverflow question that your code was modeled from, so I am going to link here for future viewers as well:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With