How to use React-Leaflet

bnevilleoneill

Brian Neville-O'Neill

Posted on January 8, 2020

How to use React-Leaflet

Written by Leigh Halliday✏️

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.

LogRocket Free Trial Banner

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=""
/>
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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]
      }
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

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.

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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]
});
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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.

Alt Text

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 — start monitoring for free.


The post How to use React-Leaflet appeared first on LogRocket Blog.

💖 💪 🙅 🚩
bnevilleoneill
Brian Neville-O'Neill

Posted on January 8, 2020

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

Sign up to receive the latest update from our blog.

Related