Tutorial: React ⚛ + Leaflet 🗺

maj07

Majuran SIVAKUMAR

Posted on January 14, 2021

Tutorial: React ⚛ + Leaflet 🗺

Hello, 👋 Today I want to share with you a small tutorial on how to use Leaflet with React.

For this, we are going to make a web app where we can find some tourist places at... Paris! 🇫🇷 🥖.

You can check the Demo on : https://react-leaflet-example.netlify.app/ 🚀

What is Leaflet?

Leaflet is the most popular open-source library for interactive maps. You can add markers to a map, make a circle, square, line, and much more interesting stuff. Check the documentation for more: https://leafletjs.com/

What we are going to do : 📝

  • Create our project and install all dependencies
  • Show a map, centered on Paris
  • Show markers on the map
  • Add a new marker on the map
  • Draw line between markers

For a sake of visibility, I will put only some part of the code in this article, but feel free to check the source code on Github repo

Installation ⚙️

First of all, let's create and install dependencies for this project.

  1. Let's create our project with create-react-app
npx create-react-app react-leaflet-example --template typescript
Enter fullscreen mode Exit fullscreen mode
  1. Install leaflet and react-leaflet
npm i -S leaflet react-leaflet
Enter fullscreen mode Exit fullscreen mode
  1. Install types (Optional if you are not using typescript):
npm i -D @types/leaflet
Enter fullscreen mode Exit fullscreen mode

Show a Map 🗺

Now that we have installed all we need, let's create a new component called Map. And add the starter code from the documentation.

It uses MapContainer, and we are passing to it some coordinates to center the map to our city.

TileLayer is used to show copyright on the Map

import { MapContainer, TileLayer } from "react-leaflet";

const Map = () => {
  const defaultPosition: LatLngExpression = [48.864716, 2.349]; // Paris position

  return (
    <div className="map__container">
      <MapContainer
        center={defaultPosition}
        zoom={13}
      >
        <TileLayer
          attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
          url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
        />
      </MapContainer>
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

screenshot

Show markers on the map 📍

Our map doesn't have any places yet. So let's add some default places. For that, I created an array of places in advance, with those attributes:

import { LatLngExpression } from "leaflet";

export interface Place {
  id: string;
  picture: string;
  title: string;
  description: string;
  seeMoreLink: string;
  position: LatLngExpression;
}
Enter fullscreen mode Exit fullscreen mode

In my application, I use redux to handle state management of places, show preview modal, etc. I skip how to create/use a store with react-redux. You can check the code on githup repo

So let's import our array of places, and use the Marker component for each place. Marker needs as props our place's position. We can also handle events like click to show a place's description.

Check more about Marker's options


import { MapContainer, TileLayer, Marker, Tooltip } from "react-leaflet";
import { LatLngExpression } from "leaflet";

const Map = ({places}) => {
  const defaultPosition: LatLngExpression = [48.864716, 2.349]; // Paris position

  const showPreview = (place) => {
    // show place's description
  }

  return (
    <div className="map__container">
      <MapContainer
        center={defaultPosition}
        zoom={13}
      >
        {places.map((place: Place) => (
          <Marker
            key={place.id}
            position={place.position} // 👈
            eventHandlers={{ click: () => showPreview(place) }}
          >
            {/* show place's title on hover the marker */}
            <Tooltip>{place.title}</Tooltip> 
          </Marker>
        ))}

        <TileLayer
          attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
          url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
        />
      </MapContainer>
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

screenshot

Add new marker on the map ➕📍

Cool! Now we have markers on our map, but how to add new places dynamically? Let's say we want to add a new place when we click on the map.

To show a new place on click, we are going to create a new component called AddMarker that will handle this and update the store.

In this component, we are going to use useMapEvents hook.

import { MapContainer, TileLayer, Marker, Tooltip, useMapEvents } from "react-leaflet";

const AddMarker = () => {
  const [position, setPosition] = useState(null);

  useMapEvents({
    click: (e) => {
      setPosition(e.latlng); // 👈 add marker

      /* CODE TO ADD NEW PLACE TO STORE (check the source code) */
    },
  });

  return position === null ? null : (
    <Marker position={position}></Marker>
  );
};
const Map = ({places}) => {
  /* ... */

  return (
    <div className="map__container">
      <MapContainer
        center={defaultPosition}
        zoom={13}
      >
        {/* ... */}
        <AddMarker/>
        {/* ... */}
      </MapContainer>
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

As we visit Paris let's add Paris-Saint-Germain's stadium ⚽️

So on click, we are showing the form to add a new place :
Screenshot

On save, the new place is added to our map 🎉.
Screenshot

Draw lines ✏️

Now that we have learned how to add markers to our map, let's try to draw a line between each marker.

For that, we are going to use Polyline component.
This component needs a list of positions to draw the line. So let's create an array of positions with our places.

I'll use useEffect to create this array only when places change.

const Map = ({ places }) => {

  const [polyLineProps, setPolyLineProps] = useState([]);

  useEffect(() => {
      setPolyLineProps(places.reduce((prev: LatLngExpression[], curr: Place) => {
        prev.push(curr.position);
        return prev
        ;
      }, []))
    }, [places]);

  return (
    <MapContainer
          center={defaultPosition}
          zoom={13}
          scrollWheelZoom={false}
          style={{ height: "100vh" }}
          zoomControl={false}
        >
    {/* ... */}
      <Polyline positions={polyLineProps} /> {/* 👈 */}
    {/* ... */}

    </ MapContainer>
  )
}
Enter fullscreen mode Exit fullscreen mode

Screenshot

Conclusion

In this article, we succeed to show a map and interact with it, like adding markers dynamically and drawing a line. To go further you can try to draw a circle or a rectangle.

Hope it helped some of you.

Thanks for reading. 😇

Source code available on Github 👈

Sources

💖 💪 🙅 🚩
maj07
Majuran SIVAKUMAR

Posted on January 14, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Tutorial: React ⚛ + Leaflet 🗺
javascript Tutorial: React ⚛ + Leaflet 🗺

January 14, 2021