How to update ReactGoogleMap after receiving data from the server?
This is how I create Google Map using react-google-maps API.
import React from "react"
import { compose, withProps } from "recompose"
import { withScriptjs, withGoogleMap, GoogleMap, Marker , Polyline} from "react-google-maps"
import TextField from "#material-ui/core/TextField";
import Button from "components/CustomButtons/Button.jsx";
import './Maps.css';
import axios from "axios";
const pathCoordinates = [
{ lat: 1.322459, lng: 103.853972 },
{ lat: 1.39227, lng: 103.752 }
];
const MyMapComponent = compose(
withProps({
googleMapURL: "https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&v=3.exp&libraries=geometry,drawing",
loadingElement: <div style={{ height: `100%` }} />,
containerElement: <div style={{ height: `80vh` }} />,
mapElement: <div style={{ height: `100%` }} />,
}),
withScriptjs,
withGoogleMap
)((props) =>
<GoogleMap
defaultZoom={12}
defaultCenter={{ lat: 1.322459, lng: 103.853972 }}
>
<div id='map_controls' class='toolbox'>
<TextField
id="date"
label="Date"
type="date"
defaultValue= ""
InputLabelProps={{
shrink: true,
style: { color: '#fff' }
}}
value={props.date}
onChange={props.handleChange('date')}
/>
<Button color="primary" onClick={props.handleSubmit}>Select Date</Button>
</div>
{console.log("drawing...............")}
{props.drawMap()}
</GoogleMap>
)
const initialState = {
date: "",
data: []
};
class Maps extends React.Component {
constructor(props) {
super(props);
this.state = initialState;
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.drawMap = this.drawMap.bind(this);
}
componentDidMount() {
console.log(" componentDidMount "+this.state.date);
}
handleChange = name => event => {
this.setState({ [name]: event.target.value });
};
handleSubmit(event) {
const input = {};
input["date"] = this.state.date;
axios.post("localhost:4000/readMap", input)
.then(response => {
console.log({response});
this.setState({data: response.data});
})
.catch(error => {console.log(error.response)});
event.preventDefault();
}
drawMap(){
if(!(this.state.date==="")){
var rows = [];
for (var i = 0; i < 2; i++) {
if(i===0){
rows.push(<Marker label= {(i+1).toString()} position={{ lat: 1.39227, lng: 103.752 }} key={i} />);
}else if(i===1){
rows.push(<Marker label= {(i+1).toString()} position={{ lat: 1.322459, lng: 103.853972 }} key={i} />);
}else{
}
}
return (<div>{rows}<Polyline
path={pathCoordinates}
geodesic={true}
options={{
strokeColor: "#ff2527",
strokeOpacity: 0.75,
strokeWeight: 2
}}
/></div>);
}else{
console.log("no date");
}
}
render() {
this.drawMap();
return (
<MyMapComponent
handleChange={this.handleChange}
handleSubmit={this.handleSubmit}
drawMap={this.drawMap}
/>
)
}
}
export default Maps;
I want to draw the marker after I receive data from the database. I successfully read the input(which is a date) from the user and send this data to a server to get the data of this date from the database. Data is successfully received and able to print it in the console. However, I have no idea how to update MyMapComponent to display the marker of this date. I run drawMap() function again after I get the data but the MyMapComponent is not updated after I run drawMap().
I found the solution.
render() {
console.log("render::::::::::::::::::::");
return (
<MyMapComponent
handleChange={this.handleChange}
handleSubmit={this.handleSubmit}
drawMap={this.drawMap}
>
{this.drawMap()}
</MyMapComponent>
)
}
Related
I am using an application that displays a Google map with react Google Maps have multiple pins installed, and the state changes by scrolling, and the active flight changes according to the state.
At that time, the center of the Google map is set to be an activity, but the Google map is re-rendered when the state changes. I don't know how to prevent rendering.
 Google Maps has NPM library. It uses react-google-maps and is implemented using hooks. I tried to return false with useEffect (), but I didn't hear it as it is. Please tell me
MapComponent(HOC)
import React from "react";
import { withGoogleMap, GoogleMap, withScriptjs, Marker, InfoWindow } from "react-google-maps";
import { compose, withProps, withHandlers, withStateHandlers } from "recompose";
const MapWithPlaces = compose(
withProps({
googleMapURL:
`https://maps.googleapis.com/maps/api/js?key=${process.env.REACT_APP_GOOGLE_PLACE_API_KEY}&libraries=geometry,drawing,places`,
loadingElement: <div style={{ height: `100%` }} />,
containerElement: <div style={{ height: "400px", width: "100%" }} />,
mapElement: <div style={{ height: "100%" }} />
}),
withStateHandlers(
props => ({
infoWindows: props.places.map(p => {
return { isOpen: false };
}),
defaultCenter: { 'lat': props.lat, 'lng': props.lng }
}),
{
onToggleOpen: ({ infoWindows }) => selectedIndex => ({
infoWindows: infoWindows.map((iw, i) => {
iw.isOpen = selectedIndex === i;
return iw;
})
})
}
),
withHandlers(() => {
const refs = {
map: undefined,
}
console.log(refs);
return {
onMapMounted: () => ref => {
refs.map = ref
},
onZoomChanged: ({ onZoomChange }) => (props) => {
const center = { 'lat': parseFloat(props.lat, 10), 'lng': parseFloat(props.lng, 10) }
refs.map.pantTo(center)
}
}
}),
withScriptjs,
withGoogleMap
)(props => (
<GoogleMap defaultZoom={props.zoom} defaultCenter={props.center} key={props.key} ref={map}>
{props.places &&
props.places.map((place, i) => {
let lat = parseFloat(place.lat, 10);
let lng = parseFloat(place.lng, 10);
return (
<Marker
id={place.id}
key={place.key}
position={{ lat: lat, lng: lng }}
title={place.name}
onClick={props.onToggleOpen.bind(this, i)}
opacity={place.key === props.step ? 1 : 0.5}
label={place.day === props.currentDay ? place.dayIndex.toString() : ''}
>
{props.infoWindows[i].isOpen && (
<InfoWindow onCloseClick={props.onToggleOpen.bind(i)}>
<div>{place.name}</div>
</InfoWindow>
)}
</Marker>
);
})}
</GoogleMap>
));
export default MapWithPlaces;
MapComponent(hooks)
import React, { useState, useEffect, useRef } from "react";
import { withGoogleMap, withScriptjs, GoogleMap, Marker, InfoWindow } from "react-google-maps";
// import mapStyles from "./mapStyles";
const MapCreate = React.memo((props) => {
// const [selectedPark, setSelectedPark] = useState(null);
const mapRef = useRef()
useEffect(() => {
console.log("props updates")
console.log(props);
const mapCenter = {
lat: parseFloat(props.places[props.step].lat, 10),
lng: parseFloat(props.places[props.step].lng, 10)
}
return false
// refMap.current.panTo(mapCenter) //move the map to new location
}, [props]);
return (
<GoogleMap defaultZoom={14} center={{ lat: props.center.lat, lng: props.center.lng }} ref={mapRef}>
{props.places && props.places.map((place, i) => {
let lat = parseFloat(place.lat, 10);
let lng = parseFloat(place.lng, 10);
return (
<Marker
id={place.id}
key={place.key}
position={{ lat: lat, lng: lng }}
title={place.name}
opacity={place.key === props.step ? 1 : 0.5}
label={place.day === props.currentDay ? place.dayIndex.toString() : ''}
>
</Marker>
)
})}
</GoogleMap>
)
})
const MapWrapped = withScriptjs(withGoogleMap(MapCreate));
export default function Map(props) {
const mapRef = useRef(null)
return (
<div style={{ width: "100%", height: "400px" }}>
<MapWrapped
googleMapURL={`https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry,drawing,places&key=${process.env.REACT_APP_GOOGLE_PLACE_API_KEY}`}
loadingElement={<div style={{ height: `100%` }} />}
containerElement={<div style={{ height: "400px", width: "100%" }} />}
mapElement={<div style={{ height: `100%` }} />}
{...props}
/>
</div>
);
}
Try #shouldcomponentupdate
shouldComponentUpdate(nextProps, nextState)
Use shouldComponentUpdate() to let React know if a component’s output
is not affected by the current change in state or props. The default
behavior is to re-render on every state change, and in the vast
majority of cases you should rely on the default behavior.
shouldComponentUpdate() is invoked before rendering when new props or
state are being received. Defaults to true. This method is not called
for the initial render or when forceUpdate() is used
I am trying to render multiple Directionrenders. To do that I am running a loop which gets all directions and then sets into the state. In the return method I can only find direction[0], but in the console I get all directions. I need a method by which I can wait till the function is finished and then render the component.
Here is the code:
import React,{useState,useEffect} from 'react'
import { withScriptjs, withGoogleMap, GoogleMap, Marker,DirectionsRenderer } from "react-google-maps"
import {useSelector} from 'react-redux'
const google = window.google = window.google ? window.google : {}
const MyMapComponent = withScriptjs(withGoogleMap((props) =>{
const dest = useSelector(state => state.setDestination)
const [direction,setdirection] = React.useState([])
const [isloaded,setisloaded] = React.useState(false)
useEffect(()=>{
direction1()
},[direction])
const direction1=()=>{
const hotel = {lat:52.333889,lng:4.888803}
const route = dest
var realdirections = []
route.unshift(hotel)
console.log(route,"rororo")
for(var i=0;i<route.length;i++){
if(route[i+1]){
const directionsService = new google.maps.DirectionsService();
const origin = { lat: route[i].lat, lng: route[i].lng };
const destination = { lat: route[i+1].lat, lng: route[i+1].lng };
directionsService.route(
{
origin: origin,
destination: destination,
travelMode: google.maps.TravelMode.DRIVING
},
(result, status) => {
if (status === google.maps.DirectionsStatus.OK) {
var current = direction
current.push(result)
// console.log(direction,"current")
setdirection(current)
} else {
console.error(`error fetching directions ${result}`);
}
}
);
}
setisloaded(true)
}
}
return(
<div>
{isloaded &&
<GoogleMap
defaultZoom={8}
defaultCenter={{ lat: -34.397, lng: 150.644 }}
>
{direction.map((v,i)=>{
// console.log(v,"vvvv")
return(
<DirectionsRenderer
directions={v}
// defaultOptions={{suppressMarkers: true}}
key={v.geocoded_waypoints[0].place_id}
/>
)
})}
</GoogleMap>
}
</div>
)
}
))
export default function Map(){
return(
<MyMapComponent
isMarkerShown
googleMapURL="https://maps.googleapis.com/maps/api/js?key=mykey"
loadingElement={<div style={{ height: `100%` }} />}
containerElement={<div style={{ height: `400px` }} />}
mapElement={<div style={{ height: `100%` }} />}
/>
)
}
in my code there is a button that is responsible for displaying markers on the map of the nearest places from your location, and when I click on it, I safely get the data of places, but the markers do not appear and the rest of the visual part (creating markers when clicking on the map) also stops working
homepage.jsx
import React, { Component } from 'react';
import './homepage.less';
import { connect } from 'react-redux';
import { saveMarkers, setMarker } from '../../actions/index';
import { Link } from 'react-router-dom';
import { GoogleMap, withScriptjs, withGoogleMap } from 'react-google-maps';
import MapComponent from '../mapComponent/mapComponent';
import store from '../../store';
class HomePage extends Component {
constructor(props) {
super(props);
this.state = {
zoom: 5,
selectedValue: 'school',
currentLatLng: {
lat: 0,
lng: 0,
},
marks: [],
loaded: this.props.loaded,
};
this.getLoadedMark = this.getLoadedMark.bind(this);
this.selectedChange = this.selectedChange.bind(this);
this.placeMarkerLoad = this.placeMarkerLoad.bind(this);
this.callback = this.callback.bind(this);
this.setMark = this.setMark.bind(this);
}
componentDidMount() {
this.getGeoLocation();
console.log(this.state.marks);
}
selectedChange(e) {
this.setState({
selectedValue: e.target.value,
});
console.log(this.state.selectedValue);
}
setMark = e => {
this.setState({
marks: [
...this.state.marks,
{ lat: e.latLng.lat(), lng: e.latLng.lng(), show: true },
],
});
};
getLoadedMark() {
this.setState({
marks: [...this.state.marks, ...this.state.loaded],
});
}
getGeoLocation = () => {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(position => {
this.setState(prevState => ({
currentLatLng: {
...prevState.currentLatLng,
lat: position.coords.latitude,
lng: position.coords.longitude,
},
}));
});
} else {
console.log('error');
}
};
placeMarkerLoad() {
/*global google*/
let center = new google.maps.LatLng(
this.state.currentLatLng.lat,
this.state.currentLatLng.lng
);
let map = new google.maps.Map(document.getElementById('map'), {
center: center,
zoom: 15,
});
let options = {
location: center,
radius: 1500,
type: this.state.selectedValue,
};
let service = new google.maps.places.PlacesService(map);
service.nearbySearch(options, this.callback);
console.log('GOT IT', options);
}
callback(results = google.maps.places.PlaceResult) {
for (let i = 1; i < results.length; i++) {
this.setState({
marks: [
...this.state.marks,
{
lat: results[i].geometry.location.lat(),
lng: results[i].geometry.location.lng(),
show: true,
},
],
});
}
console.log('RESULTS', results);
}
render() {
const { marks } = this.state;
return (
<div>
<div className="HomePage">
<Link to={`/`}>
<div className="Home">home</div>
</Link>
<Link to={`/about`}>
<div className="aboutAuthor">about</div>
</Link>
<Link to={`/authorization`}>
<div className="authorization">authorization</div>
</Link>
</div>
<button onClick={() => this.props.saveMarkers(this.state.marks)}>
save
</button>
<button onClick={this.getLoadedMark}>load</button>
<button
onClick={() => {
console.log(this.state.marks);
}}
>
state
</button>
<button className="map__button" onClick={this.placeMarkerLoad}>
nearby place
</button>
<select
className="map__button"
name="Object types"
id="1"
value={this.state.selectedValue}
onChange={this.selectedChange}
>
<option value="school">School</option>
<option value="restaurant">Restaurant</option>
<option value="pharmacy">Pharmacy</option>
<option value="gas_station">Gas station</option>
<option value="bank">Bank</option>
<option value="gym">Gym</option>
<option value="hospital">Hospital</option>
<option value="travel_agency">Travel agency</option>
<option value="supermarket">Supermarket</option>
</select>
<div
className="map"
id="map"
style={{ width: '100vw', height: '100vh' }}
>
<MapComponent
currentLocation={this.state.currentLatLng}
onMapClick={this.setMark}
currentZoom={this.state.zoom}
marks={marks}
/>
</div>
</div>
);
}
}
const mapStateToProps = state => {
return {
loaded: state.markers,
};
};
const mapDispatchToProps = {
saveMarkers,
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(HomePage);
and mapComponent.jsx
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { compose, withProps } from 'recompose';
import {
withScriptjs,
withGoogleMap,
GoogleMap,
Marker,
Circle,
} from 'react-google-maps';
const MapComponent = compose(
withProps({
googleMapURL:
'https://maps.googleapis.com/maps/api/js?key=AIzaSyCZ7z51hSWmXbLca5zETwnu_dYuW8CbtgM&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={props.currentZoom}
defaultCenter={{
lat: props.currentLocation.lat,
lng: props.currentLocation.lng,
}}
onClick={e => props.onMapClick(e)}
>
{props.marks.map((mark, index) => (
<Circle
key={index}
center={mark}
radius={41000}
options={{
strokeColor: '#66009a',
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: `#66009a`,
fillOpacity: 0.35,
zIndex: 1,
}}
/>
))}
</GoogleMap>
));
export default MapComponent;
codesandbox:https://codesandbox.io/s/github/lesha107/map
I have the google-maps-react in my project, but I don't know how to get all markers from the map?
import React, { Component } from "react";
import { Map, InfoWindow, Marker, GoogleApiWrapper } from "google-maps-react";
import "../Body/Map.css";
import marker_icon from "../../img/marker_icon.png";
import hover_icon from "../../img/hover_icon.png";
import { Grid, Row, Col } from "react-bootstrap";
/*global google*/
export class MapContainer extends Component {
constructor(props) {
super(props);
this.state = {
showingInfoWindow: false,
activeMarker: {},
selectedPlace: {}
};
}
onMarkerClick = (props, marker, e) => {
this.setState({
selectedPlace: props,
activeMarker: marker,
showingInfoWindow: true
});
};
onMapClicked = props => {
if (this.state.showingInfoWindow) {
this.setState({
showingInfoWindow: false,
activeMarker: null
});
}
};
addMarker = (mapProps, map) => {
var marker = new google.maps.Marker({
position: {},
map: map
});
};
render() {
const google = window.google;
const data = this.props.data;
return (
<div className="map-container">
<Map
google={this.props.google}
className={"map"}
zoom={1}
onClick={this.onMapClicked}
onReady={this.addMarker}
>
{data.map(item => (
<Marker
key={item.id}
title={item.name}
name={item.name}
position={{ lat: item.lat, lng: item.lng }}
onClick={this.onMarkerClick}
/>
))}
<InfoWindow
marker={this.state.activeMarker}
visible={this.state.showingInfoWindow}
>
<div className="info">
<h1>{this.state.selectedPlace.name}</h1>
</div>
</InfoWindow>
</Map>
</div>
);
}
}
export default GoogleApiWrapper({
apiKey: "AIzaSyDLgdweTnvhPnUE5yzdxcMeK876cFtMaSk"
})(MapContainer);
I had a similar issue. I wanted to remove all old markers and add a list of new markers. This is my code to fix it:
const MyMap = (props) => {
const [markers, setMarkers] = React.useState([])
React.useEffect(() => {
var markerArr = []
points.map(p => {
markerArr.push(<Marker position={{lat: p.lat, lng: p.lng}} />)
}
)
setMarkers(markerArr)
}, [])
const MarkerUpdater = (day) => {
var markerArr = []
points.map(p => {
markerArr.push(
<Marker position={{lat: p.lat, lng: p.lng}} />
)
}
)
setMarkers(markerArr)
}
return <Map> {markers} </Map>
}
NOTE
you should call MarkerUpdater everywhere you want to update markers
You probably meant to access google.maps.Marker objects, if so, you could consider the utilize Callback Refs:
1) assign ref attribute to store a reference to a Marker node:
<Marker ref={this.onMarkerMounted}
key={item.id}
title={item.name}
name={item.name}
position={{ lat: item.lat, lng: item.lng }}
/>
2) save marker instance into markerObjects array:
export class MapContainer extends Component {
constructor(props) {
super(props);
this.state = {
markerObjects: []
};
this.onMarkerMounted = element => {
this.setState(prevState => ({
markerObjects: [...prevState.markerObjects, element.marker]
}))
};
}
render() {
const google = window.google;
const data = this.props.data;
return (
<div className="map-container">
<Map
google={this.props.google}
className={"map"}
zoom={4}
defaultCenter={{ lat: -35.0317893, lng: 125.219989 }}
position={{ lat: -35.0317893, lng: 125.219989 }}
>
{data.map(item => (
<Marker ref={this.onMarkerMounted}
key={item.id}
title={item.name}
name={item.name}
position={{ lat: item.lat, lng: item.lng }}
/>
))}
</Map>
</div>
);
}
}
I'm really new in ReactJS. I want to visualize a map of Bulgaria and set markers in each city only when I receive rainfall data. For now I try with examples from this link: React google-maps
But I get an error when placing the code in my file:
106:86-93 "export 'default' (imported as 'RainMap') was not found in './components/RainMap/RainMap'
Probably the error is very small but I do not know how to fix it.
My code:
import React, { Component } from 'react';
import 'react-select/dist/react-select.css';
const google = window.google;
const fetch = require("isomorphic-fetch");
const { compose, withProps, withHandlers } = require("recompose");
const {
withScriptjs,
withGoogleMap,
GoogleMap,
Marker,
} = require("react-google-maps");
const { MarkerClusterer } = require("react-google-maps/lib/components/addons/MarkerClusterer");
const MapWithAMarkerClusterer = compose(
withProps({
googleMapURL: "https://maps.googleapis.com/maps/api/js?key=AIzaSyC4R6AN7SmujjPUIGKdyao2Kqitzr1kiRg&v=3.exp&libraries=geometry,drawing,places",
loadingElement: <div style={{ height: `100%` }} />,
containerElement: <div style={{ height: `400px` }} />,
mapElement: <div style={{ height: `100%` }} />,
}),
withHandlers({
onMarkerClustererClick: () => (markerClusterer) => {
const clickedMarkers = markerClusterer.getMarkers()
console.log(`Current clicked markers length: ${clickedMarkers.length}`)
console.log(clickedMarkers)
},
}),
withScriptjs,
withGoogleMap
)(props =>
<GoogleMap
defaultZoom={3}
defaultCenter={{ lat: 25.0391667, lng: 121.525 }}
>
<MarkerClusterer
onClick={props.onMarkerClustererClick}
averageCenter
enableRetinaIcons
gridSize={60}
>
{props.markers.map(marker => (
<Marker
key={marker.photo_id}
position={{ lat: marker.latitude, lng: marker.longitude }}
/>
))}
</MarkerClusterer>
</GoogleMap>
);
class DemoApp extends React.PureComponent {
componentWillMount() {
this.setState({ markers: [] })
}
componentDidMount() {
const url = [
// Length issue
`https://gist.githubusercontent.com`,
`/farrrr/dfda7dd7fccfec5474d3`,
`/raw/758852bbc1979f6c4522ab4e92d1c92cba8fb0dc/data.json`
].join("")
fetch(url)
.then(res => res.json())
.then(data => {
this.setState({ markers: data.photos });
});
}
render() {
return (
<MapWithAMarkerClusterer markers={this.state.markers} />
)
}
}
<DemoApp />
You didn't import your RainMap component. Where in your directory is it stored? It seems to be trying to import from components folder -> RainMap folder -> RainMap.js