React Leaflet: Add markers dynamically
I used the code below and it works successfully. In this code, the user can add only one marker in a position and it can change:
pay attention to import leaflet.css file
some times there are two errors about the image loading after adding the leaflet file. for resolving these errors, import marker-icon.png and marker-shadow.png in the import part and then define the L.Marker.prototype.options.icon link below.
if the map doesn't show, add the height and width(style={{width: '100%',height: '400px'}}) to Map tag as a style
import React from 'react';
import L from 'leaflet';
import 'leaflet/dist/leaflet.css';
import { Map, TileLayer, Marker, Popup } from 'react-leaflet';
import icon from 'leaflet/dist/images/marker-icon.png';
import iconShadow from 'leaflet/dist/images/marker-shadow.png';
class OSMap extends React.Component {
constructor() {
super();
this.state = {
markers: [[35.6892, 51.3890]],
};
}
addMarker = (e) => {
const { markers } = this.state;
markers.pop();
markers.push(e.latlng);
this.setState({ markers });
}
render() {
let DefaultIcon = L.icon({
iconUrl: icon,
shadowUrl: iconShadow
});
L.Marker.prototype.options.icon = DefaultIcon;
return (
<div>
<Map
center={[35.6892, 51.3890]}
onClick={this.addMarker}
zoom={13}
maxZoom={18}
minZoom={5}
style={{width: '100%',height: '400px'}}
>
<TileLayer
attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url='http://{s}.tile.osm.org/{z}/{x}/{y}.png'
/>
{this.state.markers.map((position, idx) =>
<Marker key={`marker-${idx}`} position={position}></Marker>
)}
</Map>
</div>
);
}
}
export default OSMap;
In order to get the most out of react-leaflet you should be thinking how you can design your map rendering in a way that the react lifecycle handles both the clicks and displaying of markers. React-leaflet handles almost all of the leaflet gruntwork for you.
You should be using the component's state or props to keep track of which markers the component is displaying. So, instead of manually calling L.marker
, you should simply render a new <Marker>
component.
Here is the react way to add a marker after clicking on the map:
class SimpleExample extends React.Component {
constructor() {
super();
this.state = {
markers: [[51.505, -0.09]]
};
}
addMarker = (e) => {
const {markers} = this.state
markers.push(e.latlng)
this.setState({markers})
}
render() {
return (
<Map
center={[51.505, -0.09]}
onClick={this.addMarker}
zoom={13}
>
<TileLayer
attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url='http://{s}.tile.osm.org/{z}/{x}/{y}.png'
/>
{this.state.markers.map((position, idx) =>
<Marker key={`marker-${idx}`} position={position}>
<Popup>
<span>A pretty CSS3 popup. <br/> Easily customizable.</span>
</Popup>
</Marker>
)}
</Map>
);
}
}
And here's a jsfiddle: https://jsfiddle.net/q2v7t59h/413/
For anyone using React Leaflet v3 (which is based on hooks and MapContainer
is used instead of Map
), you can use the following code to add markers when a point on the map is clicked:
function LocationMarkers() {
const initialMarkers: LatLng[] = [new LatLng(51.505, -0.09)];
const [markers, setMarkers] = useState(initialMarkers);
const map = useMapEvents({
click(e) {
markers.push(e.latlng);
setMarkers((prevValue) => [...prevValue, e.latlng]);
}
});
return (
<React.Fragment>
{markers.map(marker => <Marker position={marker} ></Marker>)}
</React.Fragment>
);
}
function LeafletMap() {
const mapCentre = new LatLng(51.505, -0.09);
return (
<MapContainer center={mapCentre}>
<TileLayer
attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<LocationMarkers />
</MapContainer>
);
}
This approach defines a function LocationMarkers
which can be included within the <MapContainer>...</MapContainer>
tag. The LocationMarkers
uses the useMapEvents hook to listen for map events (in this case click
) and perform an action when an event is received. useState
is used to manage to array of markers that are to be shown on the map.