I'm a new leaflet user for my Typescript and Hook based React application. In my app my current geolocation position(latitude, longitude) is taken(I've allowed the permission to the browser) using the chrome browser's geolocation API by the app and should be shown in the map with a marker. The issue is, the map is always displayed with the initial default position([0,0]). That is, the new position update taken from geolocation API is not displayed.
The issue might be simple but I couldn't understand what I'm missing here that the Leaflet map is not taking my updated position. I checked, new position values are printed correctly, even I rendered just the updated position values inside a simple div, the new values are rendered correctly. Here is my code as below. Any help is much appreciated.
App.tsx
import React from 'react';
import './App.css';
import { Container } from '@material-ui/core';
import {Route,Switch} from 'react-router-dom';
import Header from './components/Header';
import SideBar from './components/SideBar';
import ShowInGoogleMap from './components/ShowInGoogleMap';
import ShowInLeafletMap from './components/ShowInLeafletMap';
function App() {
return (
<div className="app-div">
<Header/>
<div className="main-content">
<SideBar/>
<div className="map-content">
<Switch>
<Route path="/google-map" component={ShowInGoogleMap}/>
<Route path="/leaflet-map" component={ShowInLeafletMap}/>
</Switch>
</div>
</div>
</div>
);
}
export default App;
###############################
ShowInLeafletMap.tsx - this is the function handling Leaflet map
import { LatLngExpression } from 'leaflet';
import React, { useState, useEffect } from 'react';
import 'leaflet/dist/leaflet.css';
import { MapContainer, Marker, Popup, TileLayer } from 'react-leaflet';
const ShowInLeafletMap = () => {
const [position, setPosition] = useState<LatLngExpression>([0,0]);
useEffect(() => {
if ("geolocation" in navigator) {
console.log("Available...");
navigator.geolocation.getCurrentPosition(function(cPosition) {
console.log("Latitude is :", cPosition.coords.latitude);
console.log("Longitude is :", cPosition.coords.longitude);
setPosition([cPosition.coords.latitude,cPosition.coords.longitude]);
});
} else {
console.log("Not Available");
}
}, []);
console.log('this is loaded, ', position);
return(
<MapContainer center={position} zoom={13} scrollWheelZoom={false}>
<TileLayer
attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<Marker position={position}>
<Popup>
Hi I just found Dresden
</Popup>
</Marker>
</MapContainer>
)
}
export default ShowInLeafletMap;
Here is dependency block of my package.json. I've no dev dependecies for the time being.
"dependencies": {
"@material-ui/core": "^4.11.4",
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",
"@types/googlemaps": "^3.43.3",
"@types/jest": "^26.0.15",
"@types/node": "^12.0.0",
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
"@types/react-leaflet": "^2.8.1",
"@types/react-router-dom": "^5.1.7",
"leaflet": "^1.7.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-leaflet": "^3.2.0",
"react-router-dom": "^5.2.0",
"react-scripts": "4.0.3",
"typescript": "^4.1.2",
"web-vitals": "^1.0.1"
},
In react-leaflet version 3, most props are immutable. As for the MapContainer itself:
You're better off using the whenCreated
prop to capture a reference to the underlying L.map instance in a state variable, then using leaflet methods directly:
const ShowInLeafletMap = () => {
const [map, setMap] = useState<L.Map>()
useEffect(() => {
if ("geolocation" in navigator && map) {
navigator.geolocation.getCurrentPosition(function(cPosition) {
map.panTo([cPosition.coords.latitude,cPosition.coords.longitude]);
});
}
}, [map])
return (
<MapContainer whenCreated(setMap)>
...
</MapContainer>
)
}