React Leaflet is a Frontend Library for displaying maps and markers through coordinates. Most of the setup is done on the Frontend.
- The only thing required in the backend is to add a property to the documents where you want to store a location. This array property will store two numeric values used for determining a location:
latitudeandlongitude. So the property should be structured like below inside the document Schema.
coordinates: [Number]; // this array will hold only two numeric values: [latitude, longitude]- When creating a new document, the frontend (supported by the leaflet package) will pass the values needed for the coordinates. So aside fron this change, the structure in the backend will be the same as for doing CRUD on any other type of document.
- npm install leaflet react-leaflet
All the components needed will come from react-leaflet. From leaflet we may need to use a couple of methods.
- Go to public/index.html and link the leaflet css file from leaflet.com (https://leafletjs.com/examples/quick-start/)
<link
rel="stylesheet"
href="https://unpkg.com/leaflet@1.9.2/dist/leaflet.css"
integrity="sha256-sA+zWATbFveLLNqWO2gtiw3HL/lh1giY/Inf1BJ0z14="
crossorigin=""
/>- Add a style to your base style file to give the leaflet size a proper size
/* this is the class used for a map container in leaflet. If not done, the map will have no size and be invisible */
.leaflet-container {
height: 400px; /* example */
width: 400px; /* example */
}The code below will give you a basic example of rendering a Map, the process of storing coordinates used to Create a Document and the process of displaying a Map with several Documents (each with their coordinates).
NOTE: If you want more information of each component, check the last section that explains each one, as well as their properties, or follow the official documentation at react-leaflet
- Go to the component where you have the form to create a new document and add the following code either inside or outside the form.
import { MapContainer, TileLayer, Marker, Popup } from "react-leaflet"; // for Leaflet Component imports
// ...
const [ center, setCenter ] = useState([51.505, -0.09]) // state used to define the center of the map on first render. [51.505, -0.09] is just an example.
// ...
<MapContainer center={center} zoom={13} scrollWheelZoom={false}>
<TileLayer
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
{/* invoke Marker Componentes here */}
</MapContainer>;- Create a state called
clickedPositionwhere the coordinates of the new document will be stored.
const [clickedPosition, setClickedPosition] = useState(null);- Next, create a component called
ClickMarkerthat will receives as prop:setClickedPositionto update the state with the coordinates whenever the user clicks on the map.
import { useMapEvents } from "react-leaflet/hooks";
function ClickMarker({ setClickedPosition }) {
useMapEvents({
click: (event) => {
console.log(event.latlng);
const obj = event.latlng;
setClickedPosition([obj.lat.toFixed(5), obj.lng.toFixed(5)]);
},
});
return null;
}
export default ClickMarker;- In the component where
<MapContainer>is, invoke<ClickMarker>inside<MapContainer>, right after the<TileLayer />invocation and passsetClickedPosition.
<ClickMarker setClickedPosition={setClickedPosition} />-
Click on the map, it all works correctly, you should see the coordinates in the console, as per the
console.login<ClickMarker>. -
After the
<ClickMarker>invocation, add the following code to render a Leaflet<Marker>component with the coordinates stored in the stateclickedPosition.
{ clickedPosition !== null && <Marker position={clickedPosition} /> }- Follow the regular Document Creation process in the form, using the value in
clickedPositionas the coordinates for the document.
NOTE: this flow is for a Marker that appears when the map is cliked. For a different flow with a Marker that can be dragged, see the code in the repository.
- Go to the component where you are listing all Documents that have coordinates and add a basic map, similar to the steps above.
import { MapContainer, TileLayer, Marker, Popup } from "react-leaflet"; // for Leaflet Component imports
// ...
const [ center, setCenter ] = useState([51.505, -0.09]) // this can be set to be one of the document coordinates with setCenter
// ...
<MapContainer center={center} zoom={13} scrollWheelZoom={false}>
<TileLayer
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
{/* invoke Marker Componentes here */}
</MapContainer>;- Follow a regular process of calling the backend for several Documents (including their
coordinatesproperty), then, add the.map()you would normally use to display all documents, but do it inside the<MapContainer>as below. For each document, render a<Marker>with the coordinates and a<Popup>component for the rest of the document data.
{
listOfDocuments.map((eachElement) => {
return (
<Marker position={eachElement.coordinates}>
<Popup>
{/* Example of the rest of the document data*/}
<p>Name: <b>{eachElement.name}</b></p>
</Popup>
</Marker>
);
})
}-
Similar to above, you can display a map for the details of a single Document.
-
You can modify the
centerproperty of the<MapContainer>to be the value of the first document in the list (if any exist), that way the map will always have some markers showing.
- REQUIRED. The first component that creates the map
import { MapContainer } from "react-leaflet";- (REQUIRED) center: should have an
arrayof twonumbers[latitude, longitud] - (REQUIRED) zoom: should have a
numberthat represents initial zoom value - (OPTIONAL) scrollWheelZoom: should have a
booleanto allow zoom on mouse
- REQUIRED. Added inside
MapContainer. The component that links to the openstreetmap info.
import { TileLayer } from "react-leaflet";- IMPORTANT. below line is required as it is. Should be inside
MapContainer
<TileLayer
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>- (REQUIRED) attribution: should have the following value:
'© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' - (REQUIRED) url: should have the following value:
"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
- OPTIONAL. Added inside
MapContainer. This component shows a marker on the map. - If showing multiple pins, we should iterate over the array of data and show a Marker for each element.
import { Marker } from "react-leaflet";- (REQUIRED) position: should have an
arrayof twonumbers[latitude, longitud] - (OPTIONAL) eventHandlers: accepts an object with the types of events to listen to (click, drag, dragend, etc...). As value, the function to be invoked in each event type.
- OPTIONAL. Added inside
Marker. This component shows a modal with information of the marker. The information shown is all jsx inside the component.
import { Popup } from "react-leaflet";