React - hovering over dynamically generated component calls render method - reactjs

My app contains a google map that displays markers based on coordinates from an API. Upon the loading the app, an API request is made and a few coordinates are grabbed to be displayed on the screen. The API data is mapped to a <Marker /> component.
Problem: Upon hovering over any Marker, the render method gets called again and the Markers quickly flash. Why?
Map.js
state = {
center: { lat, lng },
zoom: defaultZoom,
showingInfoWindow: false,
selectedMarker: ""
};
onMarkerHover = (e, marker) => {
this.setState({
selectedMarker: marker.recordid,
showingInfoWindow: true
});
this.onSendMarkerInfoToParent();
};
render() {
const data = this.props.searchedResponse;
console.log("rerendering"); // printed in console on every hover event
const Markers = props =>
data
? data.data.records.map(marker => {
return (
<Marker
position={{ lat: marker.fields.geom.coordinates[1], lng: marker.fields.geom.coordinates[0] }}
key={marker.recordid}
onClick={e => this.onMarkerClick(e, marker)}
onMouseOver={e => this.onMarkerHover(e, marker)}
>
{this.state.showingInfoWindow && this.state.selectedMarker === marker.recordid && (
<InfoWindow
className="info-window"
position={{ lat: marker.fields.geom.coordinates[1], lng: marker.fields.geom.coordinates[0] }}
>
<div>{rateTimeCalc(marker)}</div>
</InfoWindow>
)}
</Marker>
);
})
: null;
return (
<div className="map-container">
<LoadScript googleMapsApiKey={process.env.REACT_APP_GOOGLE_KEY}>
<GoogleMap id="map" center={this.state.center} zoom={this.state.zoom}>
<Markers />
</GoogleMap>
</LoadScript>
</div>
);
}
App.js
onSendMarkerInfoToParent = e => {
console.log("parent", e);
};

This is because of Lifecycle of React app.
You have mapped the onHover method in your code that set the state.
onMouseOver={e => this.onMarkerHover(e, marker)}
onMarkerHover = (e, marker) => {
this.setState({
selectedMarker: marker.recordid,
showingInfoWindow: true
});
this.onSendMarkerInfoToParent();
};
This setState causes re-render.
In React, whenever you set the state of a component. The render method will be executed automatically.
You can read this article for reference: https://medium.com/react-ecosystem/react-components-lifecycle-ce09239010df.

Solution for google-maps-react and Markers re-rendering:
1.Create Wrapper PureComonent for all Markers.
2.Maintain one InfoWindow for all Markers.
Working example:
https://codesandbox.io/s/falling-wave-kjcee

Related

react-map-gl load map on the location of the user

Using react 18 and react-map-gl 7.0.11, im not able to load the map on the location of the user.
I am able to get this button on the screen using the GeoLocateControl component
https://i.stack.imgur.com/fBy1y.png
<Map
{...viewState}
reuseMaps
mapStyle="mapbox://styles/mapbox/streets-v9"
mapboxAccessToken={process.env.REACT_APP_MAPBOX_KEY}
onMove={(evt) => setViewState(evt.viewState)}
>
<GeolocateControl
positionOptions={{
enableHighAccuracy: true,
}}
trackUserLocation={true}
onGeolocate={(pos) => {
setViewState({
...viewState,
longitude: pos.coords.longitude,
latitude: pos.coords.latitude,
});
}}
/>
</Map>
Is there a way, to trigger the button click to move the map and the blue dot to the current location of the user on mount of the component (map), without setting up event listeners? I tried the method of declaring a ref, and using useCallback to trigger the ref, but it did not work.
Any suggestions?
as per https://blog.logrocket.com/using-mapbox-gl-js-react/: you can do something like:
function MyMap() {
const [viewport, setViewport] = useState({});
useEffect(() => {
navigator.geolocation.getCurrentPosition((pos) => {
setViewport({
...viewport,
latitude: pos.coords.latitude,
longitude: pos.coords.longitude,
zoom: 3.5,
});
});
}, []);
return (
<div>
{viewport.latitude && viewport.longitude && (
<div>
<h1>Your Location:</h1>
<Map
mapboxAccessToken="MAPBOX_TOKEN"
initialViewState={viewport}
mapStyle="mapbox://styles/mapbox/streets-v11"
>
<Marker
longitude={viewport.longitude}
latitude={viewport.latitude}
/>
</Map>
</div>
)}
</div>
);
}

Need To back draggable marker's lat and lang to the main page from where it called

I want to work with draggable marker to collect lat and lang and after marker moving, want to take lat and lng from select using marker. My googlemap react js code is
class GoogleMaps extends Component {
constructor(props) {
super(props);
this.getLangLat = this.getLangLat.bind(this);
}
loadMap = (map, maps) => {
let marker = new maps.Marker({
position: { lat: 40.856795, lng: -73.954298 },
map,
draggable: true
});
};
getLangLat(e) {
//this.lat = e
console.log("Lat",e.lat);
console.log("Lng",e.lng);
this.lat = e.lat
this.lng = e.lng
// this.props.lat = e.lat;
//this.props.lng = e.lng;
}
render() {
return (
<div style={{ height: "400px", width: "400px" }}>
<GoogleMapReact
bootstrapURLKeys={{ key: "xxxxxxx" }}
defaultCenter={{ lat: 40.756795, lng: -73.954298 }}
defaultZoom={10}
onClick={this.getLangLat}
yesIWantToUseGoogleMapApiInternals
onGoogleApiLoaded={({ map, maps }) => this.loadMap(map, maps)}
/>
</div>
);
}
}
export default GoogleMaps;
My another page, from where is called
import GoogleMaps from './GoogleMaps';
const SignUp = ({ handleChange, newState, alert }) => {
return(
<GoogleMaps></GoogleMaps>
)
}
How can I get lang and lat from draggable marker in google map? In react Js

google map shows random location as center, even when center is specified

I'm using the package google-maps-react to show gmaps in my react app. Everything works fine, except for the fact that the map initially shows a random location as the center, even when I've specified co-ordinates for the center and initial center. How can I fix this so that the map centers on the co-ordinates I've specified initially?
const MapContainer = React.memo((props) => {
const [map, setMap] = useState();
const [center, setCenter] = useState({ lat: 59.913, lng: 10.752 });
var bounds = new props.google.maps.LatLngBounds();
const setMapObj = (mapProps, map) => {
setMap(map);
};
useDeepCompareEffect(() => {
if (props.markers.length === 1) {
setCenter(props.markers[0]);
}
for (var i = 0; i < props.markers.length; i++) {
bounds.extend(
new props.google.maps.LatLng(props.markers[i].lat, props.markers[i].lng)
);
}
if (map) {
map.fitBounds(bounds);
}
}, [props.markers, map]);
return (
<div className={props.className}>
{/* TODO -> Store api key in .env file */}
{console.log(center)}
<Map
google={props.google}
style={{ borderRadius: "10px" }}
center={center}
initialCenter={center}
onReady={setMapObj}
zoom={4}
bounds={bounds}
>
{props.markers.map((item, index) => {
if (item.lat && item.lng)
return (
<Marker key={index} position={{ lat: item.lat, lng: item.lng }} />
);
})}
</Map>
</div>
);
});
Your code is trying to set a center AND fit a particular bounds. The latter will cause the center to change in order to fit all of the markers in the viewport.

Google Maps fitBounds not centering and showing markers in google-maps-react

I'm using google-maps-react in my react app to use GMaps. This is the code I got:
function MapContainer(props) {
var bounds = new props.google.maps.LatLngBounds();
const [markers, setMarkers] = useState([
{
lat: 55.378,
lng: 3.436
},
{
lat: 37.0902,
lng: 95.712
}
]);
const adjustMap = (mapProps, map) => {
const { google } = mapProps;
markers.forEach(marker => {
bounds.extend(new google.maps.LatLng(marker.lat, marker.lng));
});
map.fitBounds(bounds);
}
return (
<>
<div className={props.className}>
<Map
google={props.google}
style={{ borderRadius: '10px'}}
zoom={7}
onReady={adjustMap}
bounds={bounds}
initialCenter={{ lat: 47.444, lng: -122.176}}
>
{
markers.map((item) => {
return (
<Marker position={{lat: item.lat, lng: item.lng}}/>
)
})
}
</Map>
</div>
<button onClick={(e) => { e.preventDefault(); const newMap = [...markers, {lat: 59.913, lng: 10.752}]; setMarkers(newMap)}}>Add marker</button>
</>
);
}
So initially, the map is centered properly, as it shows the two markers. But when I click on the button to add another marker, it just shows a random area where none of the markers are visible.
I referred to what tidyline suggested in this thread modified it slightly to fix the errors, but that didn't work. - https://github.com/fullstackreact/google-maps-react/issues/63
How can I fix this to show all the markers when other markers are added?
There are two issues going on:
onReady={adjustMap} will only execute once and not after adding more markers
you click handler sets a hard coded location for the marker and the bounds of the map is not updated with this new marker. maybe call adjustMap from the handler?

How can i get the location of the user - Using at React Map GL

I'm using React Map GL, and I want to put the latitude and longitude of the user
Returning the component like this:
export default geolocated({
positionOptions: {
enableHighAccuracy: false
},
userDecisionTimeout: 5000
})(Layout);
I'm tried to use react-geolocated but it's returning null coords.
I want to get these informations when the component mounts, that's the code:
componentDidMount() {
console.log(this.props);
if (navigator.geolocation) {
const viewport = {
...this.state.viewport,
latitude: this.props.coords.latitude,
longitude: this.props.coords.longitude
};
this.setState({ viewport });
}
}
The map component:
<MapGL
{...viewport}
//onClick={this.handleMapClick}
mapStyle="mapbox://styles/mapbox/streets-v9"
mapboxApiAccessToken={TOKEN}
perspectiveEnabled
onViewportChange={viewport => this.setState({ viewport })}
>
<div className="geo" style={geolocateStyle}>
{" "}
<GeolocateControl
positionOptions={{ enableHighAccuracy: true }}
trackUserLocation={true}
/>
</div>
<div className="nav" style={navStyle}>
<NavigationControl
onViewportChange={viewport => this.setState({ viewport })}
/>
</div>
</MapGL>
I'm getting the props like this:
{coords: null, isGeolocationAvailable: true, isGeolocationEnabled: true, positionError: null}
I don't know how to achieve this using the Geolocate control...
but an alternative would be to just use the user's device location & plain javascript to fetch the current location...
I.E. Something like this:
useEffect(() => {
navigator.geolocation.getCurrentPosition(pos => {
setViewport({
...viewport,
latitude: pos.coords.latitude,
longitude: pos.coords.longitude
});
});
}, []);
Hope this helps someone!

Resources