Leigh Halliday Leigh Halliday is a developer based out of Canada who works at FlipGive (https://www.flipgive.com). He writes about React and Ruby on his blog (https://www.leighhalliday.com) and publishes React tutorials on YouTube (https://youtube.com/leighhalliday).

How to use React-Leaflet

4 min read 1238

Most developers are familiar with Google Maps and MapBox, but both require accounts to use them, and maybe even entering credit card details. What if you wanted an open-source and free alternative? Here’s where Leaflet steps up to the plate! It’s a light-weight, open-source mapping library that utilizes OpenStreetMap.

In this article, we’ll see how to use React-Leaflet to render Leaflet maps inside of your React app. We’ll show markers with custom icons, and display a popup on the map when clicked. Later, we will see what needs to change to load remote vs local data using SWR.

The source code shown in this article is available here.

React-Leaflet installation

After adding react-leaflet to our package.json file, we’ll need to do a couple small things to get our map displaying correctly. Leaflet requires some CSS to render, and you can do that either by including the CSS link tag in your head, or you can copy/paste the CSS from the file below directly into your project:

<link
  rel="stylesheet"
  href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css"
  integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ=="
  crossorigin=""
/>

We need to also make sure to set the width/height of .leaflet-container that the map renders itself into, otherwise it won’t be visible because the div will have a height of 0px:

.leaflet-container {
  width: 100%;
  height: 100vh;
}

Once this is done we’re ready to get started! The code below shows the minimal amount required to get a Leaflet map rendering in our React app. We have imported Map from react-leaflet (along with some other packages we’ll utilize later on), and we’ll return it from our App component.

The Map component requires that we set a center position, which is an array containing latitude and longitude, along with the default zoom level of the map.

You’ll also notice the TileLayer component nested inside of Map. We are required to give attribution to OpenStreetMap, otherwise, all you’ll see is a grey square on the screen:

import React from "react";
import { Map, Marker, Popup, TileLayer } from "react-leaflet";
import { Icon } from "leaflet";
import * as parkData from "./data/skateboard-parks.json";
import "./app.css";

export default function App() {
  return (
    <Map center={[45.4, -75.7]} zoom={12}>
      <TileLayer
        url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
        attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
      />
    </Map>
  );
}

Displaying map markers

To display markers on the map we need some data. Our data comes from the city of Ottawa, containing the skateboard parks in the area. We will load this data locally from a JSON file, but to get an idea of what it looks like, here’s an example of two skateparks below:

{
  "features": [
    {
      "type": "Feature",
      "properties": {
        "PARK_ID": 960,
        "NAME": "Bearbrook Skateboard Park",
        "DESCRIPTIO": "Flat asphalt surface, 5 components"
      },
      "geometry": {
        "type": "Point",
        "coordinates": [-75.3372987731628, 45.383321536272049]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "PARK_ID": 1219,
        "NAME": "Bob MacQuarrie Skateboard Park (SK8 Extreme Park)",
        "DESCRIPTIO": "Flat asphalt surface, 10 components, City run learn to skateboard programs, City run skateboard camps in summer"
      },
      "geometry": {
        "type": "Point",
        "coordinates": [-75.546518086577947, 45.467134581917357]
      }
    }
  ]
}

With our data in place, we can map through it inside of the Map component, returning a Marker component for each of the park locations. A Marker requires a position prop, telling it where to render on the map. This is an array of [latitude, longitude], much like the center prop of the Map.

We made a custom demo for .
No really. Click here to check it out.

In addition to this, I have set up some state. Inside of the onClick prop, we will set the activePark when a user clicks on the marker. This will be used later to show some information to the user about a specific skatepark in a map popup:

 
export default function App() {
  const [activePark, setActivePark] = React.useState(null);

  return (
    <Map center={[45.4, -75.7]} zoom={12}>
      {parkData.features.map(park => (
        <Marker
          key={park.properties.PARK_ID}
          position={[
            park.geometry.coordinates[1],
            park.geometry.coordinates[0]
          ]}
          onClick={() => {
            setActivePark(park);
          }}
        />
      ))}
    </Map>
  );
}

Displaying map popups

Because we are tracking which skatepark the user has clicked on, if there is an activePark in our state, we can show a Popup. The Popup component shows a little white bubble that can be closed, and much like a Marker, we’re required to give it a position so it knows where to render on the map. Inside of the Popup we’re able to pass HTML. This can also be styled using CSS, so feel free to change the look and feel to get it looking exactly like you want.

There is an onClose prop/event on the Popup, allowing us to track when the user closes the popup bubble so we can update the state accordingly.

<Map center={[45.4, -75.7]} zoom={12}>
  {activePark && (
    <Popup
      position={[
        activePark.geometry.coordinates[1],
        activePark.geometry.coordinates[0]
      ]}
      onClose={() => {
        setActivePark(null);
      }}
    >
      <div>
        <h2>{activePark.properties.NAME}</h2>
        <p>{activePark.properties.DESCRIPTIO}</p>
      </div>
    </Popup>
  )}
</Map>

Custom marker icons

It is easy to customize marker icons in Leaflet. It is done by first using Icon, imported from leaflet itself. With that, we can create a new Icon instance, setting the URL location of the image along with its size.

import { Icon } from "leaflet";

const skater = new Icon({
  iconUrl: "/skateboarding.svg",
  iconSize: [25, 25]
});

The Marker component has an icon prop which can be set to the skater variable that we created.

Displaying remote data

Using SWR for remote data fetching, we can load our data remotely from an API endpoint. If you have never worked with SWR before, I have an article/video on how it works in React. The truth is that once you have the data, how you display it on the map is no different from local data. We are going to display some crime data provided by the UK police.

I have sliced the data to only render the first 100 crimes in the array because when rendering 1000+ markers, the map slows to a crawl:

// existing imports + new import for SWR
import useSwr from "swr";

const fetcher = (...args) => fetch(...args).then(response => response.json());

export default function App() {
  const url =
    "https://data.police.uk/api/crimes-street/all-crime?lat=52.629729&lng=-1.131592&date=2019-10";
  const { data, error } = useSwr(url, { fetcher });
  const crimes = data && !error ? data.slice(0, 100) : [];

  return (
    <Map center={[52.6376, -1.135171]} zoom={12}>
      <TileLayer
        url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
        attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
      />

      {crimes.map(crime => (
        <Marker
          key={crime.id}
          position={[crime.location.latitude, crime.location.longitude]}
        />
      ))}
    </Map>
  );
}

If you do require thousands of markers, you may want to look at either using Leaflet directly (to see if it can give you some additional performance) or seeing if Google Maps or MapBox are better suited to your needs.

Conclusion

Leaflet and its React counterpart, React-Leaflet, are a fantastic open-source and free mapping alternative to Google Maps and MapBox, no API key required! It is an easy package to work with and one worth trying out. Leaflet is an extremely light library, coming in at only 40kb of JS, and it is used by industry giants such as GitHub, Pinterest, and Etsy. Many more examples can be found on the React-Leaflet website.

Full visibility into production React apps

Debugging React applications can be difficult, especially when users experience issues that are difficult to reproduce. If you’re interested in monitoring and tracking Redux state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket.

LogRocket is like a DVR for web apps, recording literally everything that happens on your React app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app's performance, reporting with metrics like client CPU load, client memory usage, and more.

The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.

Modernize how you debug your React apps — .

Leigh Halliday Leigh Halliday is a developer based out of Canada who works at FlipGive (https://www.flipgive.com). He writes about React and Ruby on his blog (https://www.leighhalliday.com) and publishes React tutorials on YouTube (https://youtube.com/leighhalliday).

9 Replies to “How to use React-Leaflet”

  1. Very cool. Might it be a better practice to import the Map component as another name such as LeafletMap though to avoid potential future conflict with the Map data-structure?

  2. thank you thank you very much. It helped me a lot. Especially to solve errors with the marker. Nothing I had seen had worked for me but I followed your simple steps and it was perfect everything worked

  3. I am having a problem with the open street maps mapm having missing tiles and being jumbled up.

    I have a npx create-react-app with the app.css containing that leaflet-container then in the app.js I have the code below wotih the ottawa centric map I added an import ./leaflet.css as well trying to fix my tiling problem but that then gives me an error of:

    Module not found: Can’t resolve ‘./images/layers-2x.png’ in ‘D:\code\ComIT\ReactJS\comit-poject-robm\src’

  4. you have to update the map center with new position, so on click of marker u can get the markes (lat,lng) and set the same value to the map center

Leave a Reply