react-google-maps map refreshes after onclick - reactjs

I'm using react-google-maps in a Map component and whenever I click on a marker two odd things happen. First, there is two InfoWindow's opening, one blank one and one with my div. Also, whenever an onclick is performed the map refreshes which is not what I want. I am calling my Map component from App.js.
import React, { useState, Component } from'react';
import { GoogleMap, withScriptjs, withGoogleMap, Marker, InfoWindow } from "react-google-maps";
function Map(props) {
const WrappedMap = withScriptjs(withGoogleMap(CreateMap))
const [selectedPatio, setSelectedPatio] = useState(null)
function CreateMap(){
return (
<GoogleMap
defaultZoom={13}
defaultCenter={{ lat: 49.278352, lng: -123.122538 }}
>
{props.patios.map((patio) => (
<Marker
key={patio.name}
position={{
lat: patio.lat,
lng: patio.lng}}
onClick={() => {
setSelectedPatio(patio);
}}
/>
))}
{selectedPatio && (
<InfoWindow
onCloseClick={() => {
setSelectedPatio(null);
}}
position={{
lat: selectedPatio.lat,
lng: selectedPatio.lng
}}
>
<div>
asd
</div>
</InfoWindow>
)}
</GoogleMap>)
}
return (
<WrappedMap
googleMapURL={'https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=gemotry,drawing,places&key=XXX'}
loadingElement={<div style={{ height: `100%` }} />}
containerElement={<div style={{ height: `100%` }} />}
mapElement={<div style={{ height: `100%` }} />}
/>
);
}
export default Map
//This is what my render looks like in app.js where i'm calling Map and sending an array of patios to props
render() {
return (
<BrowserRouter>
<NavBar data={{ icon:"location", text1:"Map", text2:"About"}}></NavBar>
<div style={{ width: `100vw` , height: `75vh`, maxWidth: `100%` }}>
<Map patios={this.state.patios}/>
<div>
<PatioMasonry patios={this.state.patios}/>
</div>
</div>
<div>
<BottomNavBar/>
</div>
<div>
<Switch>
<Route path="/" component={Homescreen} exact/>
</Switch>
</div>
</BrowserRouter>
);
}
}

You are defining a functional component inside another functional component. By doing this, when the parent component re-renders, then a new instance of child component is created and the component is re-mounted instead of re-render. Therefore your map is getting refreshed.
Move your CreateMap component outside of Map component
import React, { useState, Component } from'react';
import { GoogleMap, withScriptjs, withGoogleMap, Marker, InfoWindow } from "react-google-maps";
const WrappedMap = withScriptjs(withGoogleMap(CreateMap))
function CreateMap(){
const [selectedPatio, setSelectedPatio] = useState(null)
return (
<GoogleMap
defaultZoom={13}
defaultCenter={{ lat: 49.278352, lng: -123.122538 }}
>
{props.patios.map((patio) => (
<Marker
key={patio.name}
position={{
lat: patio.lat,
lng: patio.lng}}
onClick={() => {
setSelectedPatio(patio);
}}
/>
))}
{selectedPatio && (
<InfoWindow
onCloseClick={() => {
setSelectedPatio(null);
}}
position={{
lat: selectedPatio.lat,
lng: selectedPatio.lng
}}
>
<div>
asd
</div>
</InfoWindow>
)}
</GoogleMap>)
}
function Map(props) {
return (
<WrappedMap
googleMapURL={'https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=gemotry,drawing,places&key=XXX'}
loadingElement={<div style={{ height: `100%` }} />}
containerElement={<div style={{ height: `100%` }} />}
mapElement={<div style={{ height: `100%` }} />}
/>
);
}
export default Map

Related

How do I re-center a GoogleMap React component to a new address using react-google-maps?

I'm rendering a GoogleMap component using the "react-google-maps" library in React. I can set an initial defaultLocation that works fine when the map initially loads. In the documentation it says that the component takes a "center" prop that one can pass a lat and a lng to but I can't get it to re-render/re-center to a new location. It always shows the default location. Any idea what I am doing wrong?
Is there maybe a way how I can use state outside of the addAdressComponent class so I can dynamically set the initial defaultCenter instead of using props in the render section?
import { withGoogleMap, GoogleMap, Marker } from 'react-google-maps';
/*global google*/
const MapWithMarker = withGoogleMap((props) => (
<GoogleMap
defaultZoom={12}
defaultCenter={{ lat: 47.376888, lng: 8.541694 }}
options={{
disableDefaultUI: true,
}}
>
<Marker position={{ lat: 47.376888, lng: 8.541694 }} />
</GoogleMap>
));
class addAddressComponent extends Component {
constructor(props) {
super(props);
this.state = {
lat: 0,
lng: 0,
};
this.onSuggestSelect = this.onSuggestSelect.bind(this);
}
onSuggestSelect(suggest) {
console.log(suggest.location);
this.setState(() => {
return {
lat: 10.0,
lng: 20.022,
};
});
}
render() {
return (
<div className="wrapperClass">
<MapWithMarker
containerElement={<div style={{ height: '244px' }} />}
mapElement={<div style={{ height: '100%' }} />}
className="mapCSS"
center={(this.state.lat, this.state.lng)}
style={{
width: '348px',
height: '250px',
}}
/>
</div>
);
}
}
export default addAddressComponent;
You'll need to pass the center property to your GoogleMap component inside your MapWithMarker component. Also the center argument needs to be an object like this:
{ lat: -34.397, lng: 150.644 }
The following example lets you change the center of the map using the button:
import logo from './logo.svg';
import './App.css';
import { withScriptjs, withGoogleMap, GoogleMap, Marker } from 'react-google-maps';
import {useState} from "react";
const MyMapComponent = withScriptjs(withGoogleMap((props) =>
<GoogleMap
defaultZoom={13}
center={props.center}
defaultCenter={{ lat: -34.397, lng: 150.644 }}
>
{props.isMarkerShown && <Marker position={{ lat: -34.397, lng: 150.644 }} />}
</GoogleMap>
))
function App() {
const [position, setPosition] = useState({ lat: -34.397, lng: 150.644 });
return (
<div className="App">
<button onClick={() => setPosition({lat: 30, lng: 10})}>,
Click me
</button>
<MyMapComponent
isMarkerShown
googleMapURL="https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry,drawing,places"
loadingElement={<div style={{ height: `100%` }} />}
containerElement={<div style={{ height: `100%` }} />}
center={position}
mapElement={<div style={{ height: `1000px`}} />}
/>
</div>
);
}
export default App;

Access variable outside render

I'm having a problem in my code. I already can make a marker on the map with lat and lng. But I want to display a simple span with the coordinates under the map. I try to access this.props.markerPosition and it's null in render.
What is the issue here?
https://stackblitz.com/edit/react-snxake
const WrappedMap = 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} onClick={props.onMarkerClick} defaultOptions={{ styles: mapStyles}} />}
</GoogleMap>
)
export default class ParkingSpotsSettings extends React.Component {
state = {
evaluationExecuted: false,
evaluation: false
};
constructor() {
super();
this.state = {
coordinates: [],
title: '',
description: '',
capacity: 0
}
}
componentDidMount() { }
render() {
return (
<div className="App">
<Navigation />
<div className="container-fluid">
<div className="row">
<div className="col-md-6" style={{ width: "100vw", height: "40vh" }}>
<WrappedMap googleMapURL={`https://maps.googleapis.com/maps/api/js?key=v=3.exp&libraries=geometry,drawing,places`}
loadingElement={<div style={{ height: "100%" }} />}
containerElement={<div style={{ height: "100%" }} />}
mapElement={<div style={{ height: "100%" }} />}
/>
</div>
<span>Coordinates are: {this.props.markerPosition}</span>
</div>
</div>
</div >
);
}
}
Your prop is called position not markerPosition. So you need to use this.props.position.

How to pass data from a parent component or use axios here in the map function for react-google-maps library?

I try to pass an array of the markers' coordinates and some other props from the index page (parent of the CardTransactionMapRGMs component) to the map function, so it can use the data to map the Markers. However, I can get the props in the CardTransactionMapRGMs, but I don't know how to get it in the Map function or how to reorganize it.
Also I'm quite confused about this "const WrapperMap = withScriptjs(withGoogleMap(Map));"
Thank you so much! Here's my code:
in index.js
<CardTransactionMapRGMs charges={this.state.charges} coordinates={this.state.coordinates} />
in CardTransactionMapRGMs.js
import React, { Component } from 'react';
import axios from 'axios';
import { GoogleMap, Marker, withScriptjs, withGoogleMap } from "react-google-maps";
import Constants from '../Constants';
import MapMarker from './MapMarker';
function Map() {
return (
<GoogleMap
defaultZoom={10}
defaultCenter={{ lat: 38.96, lng: -77.29 }}
>
//I want to use {props.coordinates.map(e)=> {
// <Marker...>}}here
<Marker position={{ lat: 38.96, lng: -77.29 }} />
</GoogleMap>
)
}
class CardTransactionMapRGMs extends Component {
render() {
const WrapperMap = withScriptjs(withGoogleMap(Map));
return (
<div>
<WrapperMap
googleMapURL={`https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry,drawing,places&key=${Constants.GOOGLE_MAP_API_KEY}`}
loadingElement={<div style={{ height: '100%' }}></div>}
containerElement={<div style={{ height: `400px` }} />}
mapElement={<div style={{ height: `100%` }} />}
/>
</div>
);
}
}
export default CardTransactionMapRGMs;
You can just use your props in your Map functional component.
function Map(props){
return <GoogleMap
defaultZoom={10}
defaultCenter={{ lat: 38.96, lng: -77.29 }}>
{props.coordinates.map(markerProps)=> <Marker {markerProps}>}
<Marker position={{ lat: 38.96, lng: -77.29 }} />
</GoogleMap>
}
CardTransactionMapRGMs.js
class CardTransactionMapRGMs extends Component {
render() {
const WrapperMap = withScriptjs(withGoogleMap(Map));
return (
<div>
<WrapperMap
googleMapURL={`https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry,drawing,places&key=${Constants.GOOGLE_MAP_API_KEY}`}
loadingElement={<div style={{ height: '100%' }}></div>}
containerElement={<div style={{ height: `400px` }} />}
mapElement={<div style={{ height: `100%` }} />}
coordinates={[{ lat: 38.96, lng: -77.29 }]}
/>
</div>
);
}
}

Blank screen in react-google-maps streetview

About 50% of the time, the StreetViewPanorama shows up as a blank screen depending on the coordinates. Is there a way to check to see if the screen will show up blank before I decide to show the street view? If it will, then I would just like to show the regular map
const StreetView = withScriptjs(
withGoogleMap(props => {
const { coordinates, address, city, state, zip } = props;
return (
<GoogleMap
defaultZoom={14}
defaultCenter={{
lat: coordinates[1],
lng: coordinates[0],
}}
>
<StreetViewPanorama
defaultPosition={{
lat: coordinates[1],
lng: coordinates[0],
}}
visible
/>
</GoogleMap>
);
}),
);
export default props => {
return (
<StreetView
{...props}
googleMapURL={`https://maps.googleapis.com/maps/api/js?key=${GOOGLE_API_KEY}&libraries=visualization`}
loadingElement={<div style={{ height: `100%` }} />}
containerElement={<div style={{ height: `800px` }} />}
mapElement={<div style={{ height: `100%` }} />}
/>
);
};
Google has an endpoint to check for valid coordinates. You can use a ternary to check the status and render a marker if the Street View doesn't exist.
const StreetView = withScriptjs(
withGoogleMap(props => {
const { coordinates, address, city, state, zip } = props;
const [streetView, setStreetView] = useState(null);
axios
.get(
`https://maps.googleapis.com/maps/api/streetview/metadata?key=${GOOGLE_API_KEY}&location=${
coordinates[1]
},${coordinates[0]}`,
)
.then(resp => setStreetView(resp.data.status));
return (
<GoogleMap
defaultZoom={14}
defaultCenter={{
lat: coordinates[1],
lng: coordinates[0],
}}
>
{streetView === 'OK' ? (
<StreetViewPanorama
defaultPosition={{
lat: coordinates[1],
lng: coordinates[0],
}}
visible
/>
) : (
<></>
)}
</GoogleMap>
);
}),
);
export default props => {
return (
<StreetView
{...props}
googleMapURL={`https://maps.googleapis.com/maps/api/js?key=${GOOGLE_API_KEY}&libraries=visualization`}
loadingElement={<div style={{ height: `100%` }} />}
containerElement={<div style={{ height: `800px` }} />}
mapElement={<div style={{ height: `100%` }} />}
/>
);
};

geolocation in React, use react-google-maps

How to change defaultCenter in react-google-maps ?
I need to find my geolocation and change default values lat and lng.
import React from "react";
import { withScriptjs, withGoogleMap, GoogleMap, Marker } from "react-google-maps";
const getLocation = () =>{
const pos = {};
const geolocation = navigator.geolocation;
if (geolocation) {
geolocation.getCurrentPosition(findLocal, showEror);
}
function findLocal(position){
pos.lat = position.coords.latitude;
pos.lng = position.coords.longitude;
}
function showEror(){console.log(Error)}
return pos;
};
const myLocation = getLocation(); // object has lat and lng
I need to transfer my data to the component MapWithAMarker next: Сenter={myLocation} and Marker position={myLocation}
class GoogleMapCenter extends React.Component{
render(){
const MapWithAMarker = withScriptjs(withGoogleMap(props =>
<GoogleMap
defaultZoom={10}
defaultCenter={{ lat: -34.397, lng: 150.644 }}>
{props.isMarkerShown && <Marker position={{ lat: -34.397, lng: 150.644 }} />}
</GoogleMap>
));
return(
<MapWithAMarker
isMarkerShown
googleMapURL="https://maps.googleapis.com/maps/api/js?key=AIzaSyC4R6AN7SmujjPUIGKdyao2Kqitzr1kiRg&v=3.exp"
loadingElement={<div style={{ height: `100%` }} />}
containerElement={<div style={{ height: `400px` }} />}
mapElement={<div style={{ height: `100%` }} />}
/>
)
}
}
export default GoogleMapCenter;
If I use this.props, it does not work.
<MapWithAMarker
center={this.props.myLocation}
position={this.props.myLocation}
isMarkerShown
googleMapURL="https://maps.googleapis.com/maps/api/js?key=AIzaSyC4R6AN7SmujjPUIGKdyao2Kqitzr1kiRg&v=3.exp"
loadingElement={<div style={{ height: `100%` }} />}
containerElement={<div style={{ height: `400px` }} />}
mapElement={<div style={{ height: `100%` }} />}
/>
or
<GoogleMap
defaultZoom={10}
defaultCenter={this.props.myLocation}>
{props.isMarkerShown && <Marker position={this.props.myLocation} />}
</GoogleMap>
Default properties like defaultCenter could only be set as initial state, center property could be used instead to re-render (center) the map.
The following example demonstrates how to center the map based on current location
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
currentLatLng: {
lat: 0,
lng: 0
},
isMarkerShown: false
}
}
showCurrentLocation = () => {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
position => {
this.setState(prevState => ({
currentLatLng: {
...prevState.currentLatLng,
lat: position.coords.latitude,
lng: position.coords.longitude
},
isMarkerShown: true
}))
}
)
} else {
error => console.log(error)
}
}
componentDidMount() {
this.showCurrentLocation()
}
render() {
return (
<div>
<MapWithAMarker
isMarkerShown={this.state.isMarkerShown}
currentLocation={this.state.currentLatLng} />
</div>
);
}
}
where
const MapWithAMarker = compose(
withProps({
googleMapURL: "https://maps.googleapis.com/maps/api/js",
loadingElement: <div style={{ height: `100%` }} />,
containerElement: <div style={{ height: `400px` }} />,
mapElement: <div style={{ height: `100%` }} />,
}),
withScriptjs,
withGoogleMap
)((props) =>
<GoogleMap
defaultZoom={8}
center={{ lat: props.currentLocation.lat, lng: props.currentLocation.lng }}
>
{props.isMarkerShown && <Marker position={{ lat: props.currentLocation.lat, lng: props.currentLocation.lng }} onClick={props.onMarkerClick} />}
</GoogleMap>
)
Demo (edit)

Resources