ReactJS Using setState() for an array of objects - javascript

I am having trouble using setStates. I stored an array of markers for my Google Map in my state and I am using a for loop to iterate through each marker in order to change the position state of the marker using Google's Geocode API.
Here is my state:
state = {
showingInfoWindow: false,
activeMarker: {},
selectedPlace: {},
markers: [
{
name: "Costco Wholesale",
address: "9151 Bridgeport Rd, Richmond, BC V6X 3L9",
position: { lat: 0, lng: 0 },
placeID: 'ChIJWc2NzuF0hlQRDu0NNhdQCjM'
} //just trying to get this one to work first before I add in the others
],
busy: []
};
Here is the function(declared inside the class):
findLatLong(){
for(let i = 0; i < this.state.markers.length; i++){
Geocode.fromAddress(this.state.markers[i].address).then(
response => {
const { lati, lngi } = response.results[0].geometry.location;
this.state.markers[i].position.setState({lat: lati, lng: lngi})
}
);
}
}
As you can see, I am passing the address contained in the same array element into the .fromAddress function and then using setState to set the lat and lng to the returned value.
I later call the function after the map renders but before the markers do:
<Map
google={this.props.google}
zoom={14}
style={mapStyles}
initialCenter={{ lat: 49.166590, lng: -123.133569 }}
>
{this.findLatLong}
{this.state.markers.map((marker, index) => (
<Marker
key={index}
onClick={this.onMarkerClick}
name={marker.name}
position={marker.position}
/>
))}
However marker's position state is not changing and is instead remaining as the filler values I passed during the initial state declaration.
Full code if it helps:
import React, { Component } from 'react';
import { Map, GoogleApiWrapper, InfoWindow, Marker } from 'google-maps-react';
import Geocode from 'react-geocode';
const key = '';
Geocode.setApiKey(key);
const mapStyles = {
width: '100%',
height: '100%'
};
export class MapContainer extends Component {
state = {
showingInfoWindow: false,
activeMarker: {},
selectedPlace: {},
markers: [
{
name: "Costco Wholesale",
address: "9151 Bridgeport Rd, Richmond, BC V6X 3L9",
position: { lat: 0, lng: 0 },
placeID: 'ChIJWc2NzuF0hlQRDu0NNhdQCjM'
}
],
busy: []
};
findLatLong(){
for(let i = 0; i < this.state.markers.length; i++){
Geocode.fromAddress(this.state.markers[i].address).then(
response => {
const { lati, lngi } = response.results[0].geometry.location;
this.state.markers[i].position.setState({lat: lati, lng: lngi})
}
);
}
}
componentDidMount() {
this.getList();
}
getList = () => {
fetch('/api/getList')
.then(res => res.json())
.then(percent => this.setState({ busy: percent }))
}
onMarkerClick = (props, marker, e) =>
this.setState({
selectedPlace: props,
activeMarker: marker,
showingInfoWindow: true
});
onClose = props => {
if (this.state.showingInfoWindow) {
this.setState({
showingInfoWindow: false,
activeMarker: null
});
}
};
render() {
return (
<Map
google={this.props.google}
zoom={14}
style={mapStyles}
initialCenter={{ lat: 49.166590, lng: -123.133569 }}
>
{this.findLatLong}
{this.state.markers.map((marker, index) => (
<Marker
key={index}
onClick={this.onMarkerClick}
name={marker.name}
position={marker.position}
/>
))}
<InfoWindow
marker={this.state.activeMarker}
visible={this.state.showingInfoWindow}
onClose={this.onClose}
>
<div>
<h4>{this.state.selectedPlace.name}</h4>
<h4>{this.state.busy}</h4>
</div>
</InfoWindow>
</Map>
);
}
}
Thank you in advance!
Attempt to fix #1
.then(
response => {
const { lati, lngi } = response.results[0].geometry.location;
this.setState(oldState => {
const newMarkers = [oldState.markers];
const modifiedMarker = newMarkers[i];
modifiedMarker.lat = lati;
modifiedMarker.lng = lngi;
return {oldState, markers: [newMarkers]};
//How do i implement the modifiedMarkers?
})

UPDATE
Actually it is better if you mutate the state just once and not inside the loop
findLatLong(){
const newMarkers = [...this.state.markers]
for(let i = 0; i < this.state.markers.length; i++){
Geocode.fromAddress(this.state.markers[i].address).then(
response => {
const { lati, lngi } = response.results[0].geometry.location;
newMarkers[i].position.lat = lati;
newMarkers[i].position.lng = lngi;
}
);
}
this.setState(oldState => {
return { ...oldState, markers: [...newMakers] };
});
}
That's no how you mutate the state, it should be something like this:
this.setState(oldState => {
const newMakers = [...oldState.makers];
const modifiedElement = newMakers[i];
modifiedElement.lat = lati;
modifiedElement.lng = lngi;
return { ...oldState, makers: [...newMakers] };
});

Related

How to show a combobox popover from #reach/combobox inside a MUI dialog component?

I'm trying to put a map from google maps API and a combobox popover from #reach/combobox inside a MUI dialog component. But I have found a problem, the combobox popover is not being shown. I realized that it is shown if it is not inside the MUI dialog component.
This is the code snippet for the google maps and combobox parts:
const libraries = ['places'];
const mapContainerStyle = {
height: '100%',
width: '100%',
};
const options = {
mapId: 'c43de04e5c01e012',
scaleControl: true,
scrollwheel: true,
mapTypeControl: false,
keyboardShortcuts: false,
zoomControl: true,
};
const center = {
lat: 43.653225,
lng: -79.383186,
};
const MapsLocation = () => {
const { isLoaded, loadError } = useLoadScript({
googleMapsApiKey: process.env.REACT_APP_GOOGLE_MAPS_API_KEY,
libraries,
});
const [markers, setMarkers] = useState({});
const [selected, setSelected] = useState(null);
const onMapClick = useCallback((e) => {
setMarkers({
lat: e.latLng.lat(),
lng: e.latLng.lng(),
time: new Date(),
});
}, []);
const mapRef = useRef();
const onMapLoad = useCallback((map) => {
mapRef.current = map;
}, []);
const panTo = useCallback(({ lat, lng }) => {
mapRef.current.panTo({ lat, lng });
mapRef.current.setZoom(14);
}, []);
if (loadError) return 'Error';
if (!isLoaded) return 'Loading ...';
return (
<>
<GoogleMap
id="map"
mapContainerStyle={mapContainerStyle}
zoom={9}
center={center}
options={options}
onClick={onMapClick}
onLoad={onMapLoad}
>
<Search panTo={panTo} setMarker={setMarkers}
<Locate panTo={panTo} />
<Marker
key={uuid()}
position={{ lat: parseFloat(markers.lat), lng: parseFloat(markers.lng) }}
onClick={() => {
setSelected(markers);
}}
icon={{
url: '/static/illustrations/retailer.svg',
origin: new window.google.maps.Point(0, 0),
anchor: new window.google.maps.Point(30, 30),
scaledSize: new window.google.maps.Size(55, 55),
}}
/>
{selected ? (
<InfoWindow
position={{ lat: selected.lat, lng: selected.lng }}
onCloseClick={() => {
setSelected(null);
}}
>
<div>
<h2>
Alert
</h2>
<p>Spotted {formatRelative(selected.time, new Date())}</p>
</div>
</InfoWindow>
) : null}
</GoogleMap>
</>
);
};
function Locate({ panTo }) {
return (
<IconButton
aria-label="compass"
onClick={() => {
navigator.geolocation.getCurrentPosition((position) => {
panTo({
lat: position.coords.latitude,
lng: position.coords.longitude,
});
});
}}
>
<ExploreIcon />
</IconButton>
);
}
function Search({ panTo, setMarker }) {
const {
ready,
value,
suggestions: { status, data },
setValue,
clearSuggestions,
} = usePlacesAutocomplete({
requestOptions: {
location: {
lat: () => 43.6532,
lng: () => -79.3832,
},
radius: 100 * 1000,
},
});
const handleInput = (e) => {
setValue(e.target.value);
};
const handleSelect = async (address) => {
setValue(address, false);
clearSuggestions();
try {
const results = await getGeocode({ address });
const { lat, lng } = await getLatLng(results[0]);
setMarker({ lat, lng, time: new Date() });
panTo({ lat, lng });
} catch (error) {
console.log('Error: ', error);
}
};
console.log('data: ', data,'status: ', status);
return (
<div className="search">
<Combobox onSelect={handleSelect}>
<ComboboxInput value={value} onChange={handleInput} disabled={!ready} placeholder="Search your location" />
<ComboboxPopover>
<ComboboxList>
{status === 'OK' && data.map(({ id, description }) => <ComboboxOption key={uuid()} value={description} />)}
</ComboboxList>
</ComboboxPopover>
</Combobox>
</div>
);
}
Then, this component is called in the MUI dialogContent component as follow:
<DialogContent dividers>
<MapsLocation />
</DialogContent>
Now it looks like this (the poopover is not being shown)
I would like to know how I can make the poopover show when it is inside the MUI dialog component.
Give zIndex style to <Combobox/> component. Like:
<Combobox style={{zIndex: 9999999999}}>
...
</Combobox>

Google maps Infowindow ReactJS

very new to react. I'm using google-maps-react-api. I have two files. Index.js and MapMarker.js. It loads a few location points with info windows already loaded. I can close the window but when clicking on the marker they do not reopen. My onCLick events do not work as I expect.
I want the case to be the markers load and I click them to show info window and then can close the window as well. I've read the docs and issues on Github but can't find the info. Thanks.
Index.js
import ReactDOM from "react-dom";
import React from "react";
import { GoogleMap, LoadScript, MarkerClusterer } from "#react-google-maps/api";
import MapMarker from "./MapMarker";
const mapOptions = {
fullscreenControl: false,
streetViewControl: false,
mapTypeControl: false,
styles: [
{
featureType: "poi",
elementType: "labels",
stylers: [
{
visibility: "off"
}
]
},
{
featureType: "transit",
elementType: "all",
stylers: [
{
visibility: "off"
}
]
}
]
};
const key = ""; // PUT GMAP API KEY HERE
const defaultLocation = {
lat: 37.9755691,
lng: 23.7361789
};
let markers = [
{
id: 1,
lat: 37.975,
lng: 23.7361789
},
{
id: 2,
lat: 37.9755,
lng: 23.7361789
},
{
id: 3,
lat: 37.976,
lng: 23.7361789
}
];
class Map extends React.Component {
state = {
isInfoOpen: false,
selectedMarkerId: null,
noOfClusters: null,
markers: markers
};
onClick = (isInfoOpen, selectedMarkerId) => {
this.setState({
isInfoOpen,
selectedMarkerId
});
};
render() {
const { isInfoOpen, selectedMarkerId } = this.state;
return (
<LoadScript googleMapsApiKey={key} >
<div>
<div
style={{
width: "100%",
height: 500,
display: "flex"
}}
>
<GoogleMap
options={mapOptions}
center={defaultLocation}
zoom={18}
onLoad={this.onMapMounted}
onIdle={this.onMapIdle}
onBoundsChanged={this.onBoundsChanged}
onZoomChanged={this.onZoomChanged}
mapContainerStyle={{ flex: 1 }}
>
<MarkerClusterer averageCenter enableRetinaIcons gridSize={60}>
{clusterer =>
this.state.markers.map(markerData => (
<MapMarker
key={markerData.id}
clusterer={clusterer}
markerData={markerData}
isSelected={markerData.id === selectedMarkerId}
isInfoOpen={
markerData.id === selectedMarkerId && isInfoOpen
}
onClick={() => this.onClick()}
/>
))
}
</MarkerClusterer>
</GoogleMap>
</div>
</div>
</LoadScript>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<Map />, rootElement);
MapMarker.js
import React from "react";
import { InfoWindow, Marker} from "#react-google-maps/api";
export default class MapMarker extends React.Component {
state = {
mapMarker: null,
activeMarker: {},
selectedPlace: {},
showingInfoWindow: false
};
onMarkerClick = (props, marker) =>
this.setState({
activeMarker: marker,
selectedPlace: props,
showingInfoWindow: true
});
onInfoWindowClose = () =>
this.setState({
activeMarker: null,
showingInfoWindow: false
});
onLoad = mapMarker => {
this.setState({
mapMarker
});
};
render() {
const { clusterer, markerData } = this.props;
const { mapMarker } = this.state;
return (
<Marker
clusterer={clusterer}
onLoad={this.onLoad}
position={{
lat: markerData.lat,
lng: markerData.lng
}}
onClick={() => this.onMarkerClick()}
>
{mapMarker && (
<InfoWindow
anchor={mapMarker}
position={{
lat: markerData.lat,
lng: markerData.lng
}}
marker={this.state.activeMarker}
onClose={this.onInfoWindowClose}
visible={this.state.showingInfoWindow}
>
<div style={{ background: "white" }}>
{"custom Infobox: " + markerData.id}
</div>
</InfoWindow>
)}
</Marker>
);
}
}
I made a couple of changes in your MapMaker.js from the codesandbox link you provided.
First, I added a state named showingInfoWindow and assign a value of false. This will be the state that will indicate if the infowindow will be shown or not.
Then, I added a function named onMarkerClick which is called everytime the Marker is clicked. This will set the state of showingInfoWindow to true.
Next, I put a condition in the return of MapMaker class, which will only show the infowindow when the showingInfoWindow is set to true.
Then, I add the onInfoWindowClose function that sets the state of showingInfoWindow back to false.
Lastly, I added the onCloseClick parameter in the and call the onInfoWindowClose function.
You can follow the code snippet below for the changes in MapMaker.js
import React from "react";
import { Marker, InfoWindow } from "#react-google-maps/api";
export default class MapMarker extends React.Component {
state = {
mapMarker: null,
showingInfoWindow: false
};
onMarkerClick = (props) => {
this.setState({
showingInfoWindow: true
});
};
onInfoWindowClose = () =>
this.setState({
showingInfoWindow: false
});
onLoad = (mapMarker) => {
this.setState({
mapMarker
});
};
render() {
const { clusterer, markerData } = this.props;
return (
<Marker
clusterer={clusterer}
onLoad={this.onLoad}
position={{
lat: markerData.lat,
lng: markerData.lng
}}
clickable
onClick={this.onMarkerClick}
>
{this.state.showingInfoWindow === true && (
<InfoWindow
position={{
lat: markerData.lat,
lng: markerData.lng
}}
onCloseClick={this.onInfoWindowClose}
>
<div>
<p>hello</p>
</div>
</InfoWindow>
)}
</Marker>
);
}
}

Info Window not showing on marker click in react-google-maps

I'm trying to get the info window of the specific markers to open when the marker is clicked. The map and markers are all appearing correctly and when I hover over a marker it shows the correct title however when I click a marker nothing happens. It's definitely recognizing that the marker was clicked as it logs
the message in the console but it just doesn't show the info window. Any help would be greatly appreciated as I've been trying to solve this problem all day.
Thanks
Map.js
import React, { Component } from "react";
import { Map, GoogleApiWrapper, Marker, InfoWindow } from "google-maps-react";
import axios from "axios";
import shortid from "shortid";
class MyMapComponent extends Component {
constructor(props) {
super(props);
this.state = {
fields: [],
location: {
lat: 51.5074,
lng: 0.1278,
},
showingInfoWindow: false,
activeMarker: {},
selectedPlace: {},
taxis: [
{
companyName: "",
address1: "",
address2: "",
town: "",
postcode: "",
phoneNumber: "",
email: "",
coords: {
lat: "",
lng: "",
},
distance: "",
},
],
};
}
async componentDidMount() {
const { lat, lng } = await this.getcurrentLocation();
this.setState((prev) => ({
fields: {
...prev.fields,
location: {
lat,
lng,
},
},
currentLocation: {
lat,
lng,
},
}));
}
getcurrentLocation() {
this.getNearbyTaxis();
if (navigator && navigator.geolocation) {
return new Promise((resolve, reject) => {
navigator.geolocation.getCurrentPosition((pos) => {
const coords = pos.coords;
resolve({
lat: 51.5074,
lng: 0.1278,
/*
lat: coords.latitude,
lng: coords.longitude,
*/
});
console.log(coords.latitude, coords.longitude);
this.setState({
location: {
lat: 51.5074,
lng: 0.1278,
},
});
});
});
}
return {
lat: 0,
lng: 0,
};
}
addMarker = (location, map) => {
this.setState((prev) => ({
fields: {
...prev.fields,
location,
},
}));
map.panTo(location);
};
getNearbyTaxis = () => {
axios
.get(
`https://api.tfl.gov.uk/Cabwise/search?lat=${this.state.location.lat}&lon=${this.state.location.lng}`
)
.then((res) => {
res.data.Operators.OperatorList.map((taxi) => {
this.setState({
taxis: this.state.taxis.concat({
companyName: taxi.TradingName,
address1: taxi.AddressLine1,
address2: taxi.AddressLine2,
town: taxi.Town,
postcode: taxi.Postcode,
phoneNumber: taxi.BookingsPhoneNumber,
email: taxi.BookingsEmail,
coords: {
lat: taxi.Latitude,
lng: taxi.Longitude,
},
distance: taxi.Distance,
}),
});
});
})
.then(console.log(this.state.taxis));
};
handleToggle = () => {
console.log("marker clicked");
this.setState({
isOpen: true,
});
console.log(this.state.isOpen);
};
render() {
return (
<>
<button onClick={this.getNearbyTaxis}>Get Taxis</button>
<Map
google={this.props.google}
style={{
width: "100%",
height: "100%",
}}
initialCenter={this.state.fields.location}
center={this.state.fields.location}
zoom={14}
//onClick={this.onMapClicked}
key={shortid.generate()}
>
{this.state.taxis.length &&
this.state.taxis.map((taxi) => {
return (
<Marker
title={taxi.companyName}
name={taxi.companyName}
position={taxi.coords}
onClick={this.handleToggle} // marker ID is the key here.
key={shortid.generate()}
>
<InfoWindow
key={shortid.generate()}
visible={this.state.isOpen}
onCloseClick={this.handleToggle}
>
<div key={shortid.generate()}>
<h1 key={shortid.generate()}> hji </h1>
</div>
</InfoWindow>
</Marker>
);
})}
<Marker position={this.state.fields.location} />
</Map>
</>
);
}
}
export default GoogleApiWrapper({
apiKey: "MY_API_KEY",
})(MyMapComponent);
TaxiList.js
import React, { useState } from "react";
import { Map, GoogleApiWrapper, InfoWindow, Marker } from "google-maps-react";
import MyMapComponent from "./Map";
function TaxiList(props) {
return (
<div>
<MyMapComponent />
</div>
);
}
export default TaxiList;
In the class constructor the initial assignment of this.state = {} is missing property isOpen.
Since you pass that boolean to InfoWindow, is the component's visible prop supposed to do what you think it does? If yes, then the code should kind of work now. If no, you might want to change your code.
Aditionally, every Marker will use the same variable, which means that every related InfoWindow will show up. To solve this you might want to make use of activeMarker you have lying around there in the initial assignment of this.state = {}.
Edit: The InfoWindow won't show because it's nested. Either change Marker component, or move it outside. Documentation here: https://reactjs.org/docs/render-props.html

React Native Navigation v1 crashing in statTabBasedApp

When I navigate my app in startTabBasedApp (My 3 tabs) 1st screen to Render is the EventMap.js this is where my App crash. I just do not know why it crashing I tried to put console.log in all part of my codes but no error appeared.
So the main problem here is in the EventMap.js, because when I tried to remove the EventMap.js in my startTabBasedApp (Main Tabs) then uninstall the app, run react-native run-android, open the App navigate the Tabs (2) it works fine.
What I'm trying to do in my App is when user open the it and navigate it to the EventMap.js I want to get user's location instantly, just like in the Grab App.
How can I achieve this without crashing the App?
Here are my codes for EventMap.js
class EventMap extends Component {
constructor(props) {
super(props);
this.state = {
focusedLocation: {
latitude: 0,
longitude: 0,
latitudeDelta: 0.01,
longitudeDelta: Dimensions.get('window').width / Dimensions.get('window').height * 0.01
},
locationChosen: false,
markerPosition: {
latitude: 0,
longitude: 0
}
}
}
componentDidMount() {
this.didMountGetUserLocation();
};
//This is getting the location and exactly/automatically when they open
didMountGetUserLocation = () => {
navigator.geolocation.getCurrentPosition(pos => {
var lat = parseFloat(pos.coords.latitude)
var long = parseFloat(pos.coords.longitude)
var initialRegion = {
latitude: lat,
longitude: long,
latitudeDelta: 0.01,
longitudeDelta: Dimensions.get('window').width / Dimensions.get('window').height *0.01
};
this.setState({focusedLocation: initialRegion})
this.setState({locationChosen: true})
this.setState({markerPosition: initialRegion})
},
err => {
console.log(err);
});
};
pickLocationHandler = (event) => {
const coords = event.nativeEvent.coordinate;
//For animation of map
this.map.animateToRegion({
...this.state.focusedLocation,
latitude: coords.latitude,
longitude: coords.longitude
});
this.setState(prevState => {
return {
focusedLocation: {
...prevState.focusedLocation,
latitude: coords.latitude,
longitude: coords.longitude
},
locationChosen: true
};
});
};
getLocationHandler = () => {
navigator.geolocation.getCurrentPosition(pos => {
const coordsEvent = {
nativeEvent: {
coordinate: {
latitude: pos.coords.latitude,
longitude: pos.coords.longitude
}
}
};
this.pickLocationHandler(coordsEvent);
},
err => {
console.log(err);
alert("Fetching failed");
})
};
render() {
let marker = null;
if(this.state.locationChosen) {
marker = <MapView.Marker coordinate={this.state.markerPosition}/>
}
return(
<View style={{zIndex: -1}}>
<TouchableOpacity onPress={this.getLocationHandler} style={styles.iconContainer}>
<Icon name="md-locate" size={30} color="blue"/>
</TouchableOpacity>
<MapView
style={styles.map}
initialRegion={this.state.focusedLocation}
onPress={this.pickLocationHandler}
showsUserLocation={true}
ref={ref => this.map = ref} //For animating map movement
>
{marker}
</MapView>
</View>
);
}
}

Google is not defined using react google maps?

I have read the other questions related to this and tried implementing what the answers were on there.
They recommended adding /*global google */ - did not work
Next was to add const google = window.google; - did not work
I will post the code below and the error.
The error is happening where new google.maps is being called
Map.js:
/* global google */
import { default as React, Component } from 'react';
import raf from 'raf';
import canUseDOM from 'can-use-dom';
const google = window.google;
import { withGoogleMap, GoogleMap, Circle, InfoWindow, Marker } from 'react-google-maps';
import withScriptjs from 'react-google-maps/lib/async/withScriptjs';
const googleMapURL =
'https://maps.googleapis.com/maps/api/js?v=3.27&libraries=places,geometry&key=AIzaSyA7XEFRxE4Lm28tAh44M_568fCLOP_On3k';
const geolocation =
canUseDOM && navigator.geolocation
? navigator.geolocation
: {
getCurrentPosition(success, failure) {
failure("Your browser doesn't support geolocation.");
},
};
const GeolocationExampleGoogleMap = withScriptjs(
withGoogleMap(props =>
<GoogleMap defaultZoom={8} center={props.center}>
{props.center &&
<InfoWindow position={props.center}>
<div>User's Location</div>
</InfoWindow>}
{props.center &&
<Circle
center={props.center}
radius={props.radius}
options={{
fillColor: 'red',
fillOpacity: 0.2,
strokeColor: 'red',
strokeOpacity: 1,
strokeWeight: 1,
}}
/>}
>
{props.markers.map((marker, index) => {
const onClick = () => props.onMarkerClick(marker);
const onCloseClick = () => props.onCloseClick(marker);
return (
<Marker
key={index}
position={marker.position}
title={(index + 1).toString()}
onClick={onClick}
>
{marker.showInfo &&
<InfoWindow onCloseClick={onCloseClick}>
<div>
<strong>
{marker.content}
</strong>
<br />
<em>The contents of this InfoWindow are actually ReactElements.</em>
</div>
</InfoWindow>}
</Marker>
);
})}
</GoogleMap>,
),
);
function generateInitialMarkers() {
const southWest = new google.maps.LatLng(-31.203405, 125.244141);
const northEast = new google.maps.LatLng(-25.363882, 131.044922);
const lngSpan = northEast.lng() - southWest.lng();
const latSpan = northEast.lat() - southWest.lat();
const markers = [];
for (let i = 0; i < 5; i++) {
const position = new google.maps.LatLng(
southWest.lat() + latSpan * Math.random(),
southWest.lng() + lngSpan * Math.random(),
);
markers.push({
position,
content: 'This is the secret message'.split(' ')[i],
showInfo: false,
});
}
return markers;
}
export default class GeolocationExample extends Component {
constructor(props) {
super(props);
super(props);
this.state = {
center: null,
content: null,
radius: 6000,
markers: generateInitialMarkers(),
};
const isUnmounted = false;
handleMarkerClick = this.handleMarkerClick.bind(this);
handleCloseClick = this.handleCloseClick.bind(this);
}
handleMarkerClick(targetMarker) {
this.setState({
markers: this.state.markers.map((marker) => {
if (marker === targetMarker) {
return {
...marker,
showInfo: true,
};
}
return marker;
}),
});
}
handleCloseClick(targetMarker) {
this.setState({
markers: this.state.markers.map((marker) => {
if (marker === targetMarker) {
return {
...marker,
showInfo: false,
};
}
return marker;
}),
});
}
componentDidMount() {
const tick = () => {
if (this.isUnmounted) {
return;
}
this.setState({ radius: Math.max(this.state.radius - 20, 0) });
if (this.state.radius > 200) {
raf(tick);
}
};
geolocation.getCurrentPosition(
(position) => {
if (this.isUnmounted) {
return;
}
this.setState({
center: {
lat: position.coords.latitude,
lng: position.coords.longitude,
},
content: 'Location found using HTML5.',
});
raf(tick);
},
(reason) => {
if (this.isUnmounted) {
return;
}
this.setState({
center: {
lat: 60,
lng: 105,
},
content: `Error: The Geolocation service failed (${reason}).`,
});
},
);
}
componentWillUnmount() {
this.isUnmounted = true;
}
render() {
return (
<GeolocationExampleGoogleMap
googleMapURL={googleMapURL}
loadingElement={<div style={{ height: '100%' }}>loading...</div>}
containerElement={<div style={{ height: '100%' }} />}
mapElement={<div style={{ height: '100%' }} />}
center={this.state.center}
content={this.state.content}
radius={this.state.radius}
onMarkerClick={this.handleMarkerClick}
onCloseClick={this.handleCloseClick}
markers={this.state.markers}
/>
);
}
}
You are loading async script. When you initialize google constant there is no google object. You can solve this by using 'ref' for map component. Ref callback fired when google object exists. For example:
<GoogleMap defaultZoom={8} center={props.center} ref={()=>{props.onMapLoad}}>...</GoogleMap>
...
constructor(props) {
...
this.onMapLoad = this.onMapLoad.bind(this)
}
...
onMapLoad() {
/*init markers and all objects with "google" here*/
}
...
<GeolocationExampleGoogleMap
onMapLoad={this.onMapLoad}
...
/>
and, of course, do not init google const, use just google object instead,

Categories