I have the below JS code
A map renders just fine and when clicking the 1st click on the map, it creates and pins a marker on the place it was clicked. The 2nd time I click, it creates a 2nd marker and pins to the position that was clicked. Great!
However, when clicking the 3rd time, it doesn't create another marker! It instead moves the 2nd marker to the position of the 3rd click! Why is it doing that? It's supposed to create a 3rd marker, but for some reason, it moves the 2nd marker to a new position which should not be the case.
The marker is inside the tags too <Marker key={i} position={latLng} so it should work properly...
It seems that {props.isMarkerShown && <Marker position={props.markerPosition} />} is not creating a new instance for the marker after the 2nd marker is created for some reason...
import React from 'react';
import { compose, withStateHandlers } from "recompose";
import { InfoWindow, withGoogleMap, withScriptjs, GoogleMap, Marker } from 'react-google-maps';
const Map = compose(
withStateHandlers(() => ({
isMarkerShown: false,
markerPosition: null
}), {
onMapClick: ({ isMarkerShown }) => (e) => ({
markerPosition: e.latLng,
isMarkerShown:true
})
}),
withScriptjs,
withGoogleMap
)
(props =>
<GoogleMap
defaultZoom={8}
defaultCenter={{ lat: -34.397, lng: 150.644 }}
onClick={props.onMapClick}
>
{props.isMarkerShown && <Marker position={props.markerPosition} />}
</GoogleMap>
)
export default class MapContainer extends React.Component {
constructor(props) {
super(props)
}
render() {
return (
<div style={{ height: '100%' }}>
<Map
googleMapURL="https://maps.googleapis.com/maps/api/js?key=VALIDAPIKEY"
loadingElement={<div style={{ height: `100%` }} />}
containerElement={<div style={{ height: `400px` }} />}
mapElement={<div style={{ height: `100%` }} />}
/>
{clicks.map((latLng, i) => (
<Marker key={i} position={latLng} />
))}
</div>
)
}
}
https://developers.google.com/maps/documentation/javascript/react-map
Related
I got this react-google-maps component it is working and I receive all the data from the different locations but the console gives me this error message:
Warning: Each child in a list should have a unique "key" prop.
In my component, I've added a unique key tho.. what's the problem?
I import the map component on the page simply like that <Map />.
import React from 'react'
import { GoogleMap, Marker, withGoogleMap, withScriptjs, InfoWindow } from "react-google-maps"
import { useStaticQuery, graphql } from "gatsby"
const Map = () => {
const data = useStaticQuery(graphql`
{
allContentfulHotels {
nodes {
id
title
location {
lat
lon
}
}
}
}
`)
const {
allContentfulHotels: { nodes: locations },
} = data
return (
<>
{locations.map(({ location }) => {
console.log(location);
return (
<GoogleMap
key={location.id}
defaultZoom={15}
defaultCenter={{
lat: location.lat,
lng: location.lon,
}}
>
<Marker
key={location.id}
position={{
lat: location.lat,
lng: location.lon,
}}
>
</Marker>
</GoogleMap>
)
})}
</>
)
}
const MapComponent = withScriptjs(withGoogleMap(Map));
const MyMap = () => (
<div>
<div
style={{ width: '100%' }}
>
<MapComponent
isMarkerShown
loadingElement={<div style={{ height: `100%` }} />}
containerElement={<div style={{ height: `500px` }} />}
mapElement={<div style={{ height: `100%` }} />}
/>
</div>
</div>
)
export default MyMap
Hope someone knows what the problem is.
For Example: I am Using map function as below and set unique key..
{locations.map(({ location }, index) => {
console.log(location);
console.log(index);
return (
<GoogleMap
key={index}
defaultZoom={15}
defaultCenter={{
lat: location.lat,
lng: location.lon,
}}
Looks like you're specifying the same key for <GoogleMap /> and <Marker /> component, try setting different keys for components:
<GoogleMap
key={`map-${location.id}`}
defaultZoom={15}
defaultCenter={{
lat: location.lat,
lng: location.lon,
}}
>
<Marker
key={`marker-${location.id}`}
position={{
lat: location.lat,
lng: location.lon,
}}
>
</Marker>
</GoogleMap>
I have played around with the geolocation of javascript. So I created a react component, which shows your current location. I want to visualize this with Google Maps. It works fine so far, but however, if the current position moves outside the start map, the map does not pan. My goal is that the marker is always centered, and the map scrolls.
This is what I have so far. The current position is being passed to the component via the props props.latitude and props.longitude.
UPDATE
Now I know why this is not working.
window.google.maps.Map(document.getElementsByClassName("google-map"))
is not working. It does not find the map this way. So it cannot update its properties.
Anybody an idea how to access the current map?
Here is the code:
import React, {useState,useRef,useCallback} from 'react';
import { compose, withProps } from "recompose"
import { withScriptjs, withGoogleMap, GoogleMap, Marker } from "react-google-maps"
function Map(props) {
const [center, setCenter] = useState({ lat: props.latitude, lng: props.longitude });
const refMap = useRef(null);
const handlePositionChanged = () => {
let position = new window.google.maps.LatLng(parseInt(props.latitude), parseInt(props.longitude));
window.google.maps.Marker(document.getElementsByClassName("google-map-marker")).setPosition(position);
window.google.maps.Map(document.getElementsByClassName("google-map")).setCenter(position);
};
return (
<GoogleMap
className="google-map"
ref={refMap}
defaultZoom={19}
mapTypeId='satellite'
defaultCenter={{ lat: props.latitude, lng: props.longitude }}
onBoundsChanged={useCallback(handlePositionChanged)}
>
<Marker className="google-map-marker" position={{ lat: props.latitude, lng: props.longitude }} position_changed={useCallback(handlePositionChanged)} />
</GoogleMap>
);
}
export default compose(
withProps({
googleMapURL: "https://maps.googleapis.com/maps/api/js?key=AIz&v=3.exp&libraries=geometry,drawing,places",
loadingElement: <div style={{ height: `100%` }} />,
containerElement: <div style={{ height: `500px` }} />,
mapElement: <div style={{ height: `100%` }} />,
}),
withScriptjs,
withGoogleMap
)((props) => <Map latitude={props.latitude} longitude={props.longitude} />);
Instead of setting the center of the map and the marker using window.google.maps., you can use state values to change the <GoogleMap/> center parameter and the <Marker/> position parameter. So every time there's a change in the coordinates from geolocation, you need to change the state value of the Map's center and Marker's position and it the changes will then be reflected to the map. Here's a sample code snippet:
import React, { Component } from 'react';
import { withGoogleMap, GoogleMap, Marker } from 'react-google-maps';
class Map extends Component {
constructor(props) {
super(props);
this.state = {
userPosition: { lat: 40.756795, lng: -73.954298 }
};
}
onMapLoad = () => {
navigator.geolocation.getCurrentPosition(position => {
const { latitude, longitude } = position.coords;
this.setState({
userPosition: { lat: latitude, lng: longitude }
});
});
};
render() {
const GoogleMapExample = withGoogleMap(props => (
<GoogleMap
center={this.state.userPosition}
defaultZoom={13}
onLoad={this.onMapLoad()}
>
<Marker position={this.state.userPosition} />
</GoogleMap>
));
return (
<div>
<GoogleMapExample
containerElement={<div style={{ height: `500px`, width: '500px' }} />}
mapElement={<div style={{ height: `100%` }} />}
/>
</div>
);
}
}
export default Map;
I am working with google maps in reactjs, i need to pass the reference of the google map object, in order to send it in a function and further apply the functions associated with it. Basically i want to use the getCenter() method on the map object.. Refer this link: https://tomchentw.github.io/react-google-maps/
This is my map component from which i want the reference of my mapObject.
const MyMapComponent = compose(
withProps({
googleMapURL:
"https://maps.googleapis.com/maps/api/js?key=iDl-
mPD1j0K6lTEiMhs3D8axW53U&v=3.exp&libraries=geometry,drawing,places",
loadingElement: <div style={{ height: `100%` }} />,
containerElement: <div style={{ height: `400px` }} />,
mapElement: <div id="mapid" style={{ height: `100%` }} />
}),
lifecycle({
componentWillMount() {
console.log("Method called");
const refs = {}
this.setState({
bounds: null,
center: {
lat: 0, lng: 0
},
})
},
}),
withScriptjs,
withGoogleMap
)(props => (
<GoogleMap defaultZoom={15} defaultCenter={{ lat: props.lat, lng: props.lng
}} onCenterChanged={props.onChange(googlemapobjectref)}>
{props.isMarkerShown && (
<Marker position={{ lat: props.lat, lng: props.lng }} />
)}
</GoogleMap>
));
And in the App component (Parent Component) I want to use reference of the map object in the onChange() function.
class App extends Component {
constructor(props){
super(props);
this.state=
{
....
};
this.onChange = this.onChange.bind(this);
}
onChange(googlemapobjectref){
const val = googlemapobjectref.getCenter();
}
I just want to use getCenter() method in this code. If i am wrong at some point plz mention and if anything is not clear, mention that too. I will try to make it clear. Thanx in advance
I took the react-google-maps MapWithAMarker example :
import React from 'react';
import { compose, withProps, lifecycle} from 'recompose';
import {
withScriptjs,
withGoogleMap,
GoogleMap,
Marker,
} from 'react-google-maps';
import keys from '../../components/config/keys';
const MapWithAMarker = compose(
withProps({
googleMapURL: `https://maps.googleapis.com/maps/api/js?key=${keys.google_maps_api_key}&v=3.exp&libraries=geometry,drawing,places`,
loadingElement: <div style={{ height: '100%' }} />,
containerElement: <div style={{ height: '400px' }} />,
mapElement: <div style={{ height: '100%' }} />,
}),
withScriptjs,
withGoogleMap
)(props =>
<GoogleMap
defaultZoom={8}
defaultCenter={{ lat: props.lat, lng: props.lng }}>
<Marker position={{ lat: props.lat, lng: props.lng }}/>
</GoogleMap>
);
export default MapWithAMarker;
and I use it like this:
<MapWithAMarker lat={parseFloat(excursion.lat)}
lng={parseFloat(excursion.lng)} />
I use React router in my application.
Observed behaviour :
When i render the page for the first time, the map renders correctly.
If i click on a link to rerender the page with a different marker position, the map fails to load and just renders a empty grey rectangle with only "press ctrl plus scroll to zoom" when i scroll on it.
Solved :
I needed to change the defaultCenter to center and defaultZoom to zoom :
<GoogleMap zoom={8}
center={{ lat: props.lat, lng: props.lng }}>
<Marker position={{ lat: props.lat, lng: props.lng }}/>
</GoogleMap>
I'm using react-google-maps to display a map with markers, and when you click on a marker, all the info windows open up. I would like to display only one marker's info window when I click on it, and for the others to stay closed.
Here is my code:
<GoogleMap
defaultZoom={15}
defaultCenter={{ lat: 51.508530, lng: -0.076132 }}
>
{props.places && props.places.map((place, i) =>
<Marker onClick={props.onToggleOpen} key={i} position={{ lat: place.geometry.location.lat(), lng: place.geometry.location.lng() }} >
{props.isOpen && <InfoWindow onCloseClick={props.onToggleOpen}>
<div>{place.name}</div>
</InfoWindow>}
</Marker>
)}
</GoogleMap>
And I'm opening and closing the InfoWindow with this
import { compose, withProps, withStateHandlers, withHandlers, withState } from "recompose";
...
withStateHandlers(() => ({
isOpen: false,
}), {
onToggleOpen: ({ isOpen, id }) => () => ({
isOpen: !isOpen,
})
}),
I'm mapping over all the markers, and displaying them on the map. How could I click open just one marker InfoWindow?
Here is a related question, but it's not made with React, and doesn't use the react-google-maps.
It's more of a React question. You can pass the index of a clicked Marker to onToggleOpen and instead of isOpen you use a selectedPlace state that holds the index of a clicked Marker and use this index to render the right InfoWindow.
Here is an example (not fully tested, but you can get the idea):
/*global google*/
import React from "react"
import { compose, withProps, withHandlers, withState, withStateHandlers } from "recompose"
import { withScriptjs, withGoogleMap, GoogleMap, Marker, InfoWindow } from "react-google-maps"
const MyMapComponent = compose(
withProps({
googleMapURL: "https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry,drawing,places",
loadingElement: <div style={{ height: `100%` }} />,
containerElement: <div style={{ height: `400px` }} />,
mapElement: <div style={{ height: `100%` }} />,
}),
withScriptjs,
withGoogleMap,
withState('places', 'updatePlaces', ''),
withState('selectedPlace', 'updateSelectedPlace', null),
withHandlers(() => {
const refs = {
map: undefined,
}
return {
onMapMounted: () => ref => {
refs.map = ref
},
fetchPlaces: ({ updatePlaces }) => {
let places;
const bounds = refs.map.getBounds();
const service = new google.maps.places.PlacesService(refs.map.context.__SECRET_MAP_DO_NOT_USE_OR_YOU_WILL_BE_FIRED);
const request = {
bounds: bounds,
type: ['hotel']
};
service.nearbySearch(request, (results, status) => {
if (status == google.maps.places.PlacesServiceStatus.OK) {
console.log(results);
updatePlaces(results);
}
})
},
onToggleOpen: ({ updateSelectedPlace }) => key => {
updateSelectedPlace(key);
}
}
}),
)((props) => {
console.log(props);
return (
<GoogleMap
onTilesLoaded={props.fetchPlaces}
ref={props.onMapMounted}
onBoundsChanged={props.fetchPlaces}
defaultZoom={15}
defaultCenter={{ lat: 51.508530, lng: -0.076132 }}
>
{props.places && props.places.map((place, i) =>
<Marker onClick={() => props.onToggleOpen(i)} key={i} position={{ lat: place.geometry.location.lat(), lng: place.geometry.location.lng() }}>
{props.selectedPlace === i && <InfoWindow onCloseClick={props.onToggleOpen}>
<div>
{props.places[props.selectedPlace].name}
</div>
</InfoWindow>}
</Marker>
)}
</GoogleMap>
)
})
export default class MyFancyComponent extends React.PureComponent {
render() {
return (
<MyMapComponent />
)
}
}