Creating a React-Leaflet Custom Component Using Hooks

How to Create your own Leaflet Components to use in your React Maps.

Lucas Andión
Sep 21 · 5 min read
Image for post
Image for post
Photo by Timo Wielink on Unsplash

In my previous post I showed how easy it is to set up your own maps using React-Leaflet, and even drop some markers and popups on them.

Leaflet provides every basic map functionality you need but it’s meant to be as lightweight as possible. To go beyond that there are hundreds of third-party plugins providing different tiles, ways of loading and displaying external data, custom markers and paths, etc.

React-Leaflet provides the same core functionality but does not support any Leaflet plugin. There are a few third party plugins ported to React-Leaflet, but most of the ecosystem present in Leaflet is missing.

The recommended approach when you need extra functionality is to create your own React-Leaflet components.

Custom Components

To create your component, you will have to extend the appropriate abstract class from the ones exposed by React-Leaftlet.

You can extend:

  • MapControl
    Meant for controls, handles positioning.
  • ControlledLayer
    Base class to handle adding and removing layers.
  • MapEvented
    Base class that handles event bindings. Except MapControl and ControlledLayer, the rest of the base components inherit from this one. That includes the Map component, the top-level component that instantiates a Leaflet map and provides it to its children.
  • MapComponent
    Base class handling map panes. Panes are DOM elements used to control the ordering of layers on the map.
  • MapLayer
    Base class extending MapComponent, handles adding and removing the layer to the map when relevant. Exposes the layer in layerContainer.
  • GridLayer
    For creating tile layers, handles opacity and z-index.
  • DivOverlay
    Handles shared logic for Popup and Tooltip components.
  • Path
    Extends MapLayer with methods to style paths.

There’s not a lot of examples of custom components out there, but most of what I’ve seen that does not have to do with tile layers extend MapControl.

MapControl handles positioning and it’s a good fit if what you are trying to show on your map does not need to fill all of it or depends on a geographical position.

Our Example

Following our previous example we will be creating a map that shows a list of markers with Unesco Heritage sites and shows a legend on the bottom of the map when we select one instead of the classic popup.

Most of our components will re-use the existing ones, we will have a HeritageMap, using our existing MyMap component, but this time using only one provider. The stamen watercolor provider with its hand-made look seems like a nice choice for this.

Our HeritageMap will receive a list of heritage sites and print a marker for each of them. No custom components here, just reusing the existing ones.

A Leaflet map knows what area to show using either:

  • Thebounds prop: two geographical points defining a square that has to fit inside the map.
  • A center point and zoom value.

When there is no Marker selected we calculate the map bounds using Leaflet’s latLngBound. By extending the bounds with the positions of all the markers we get a a final result that includes them all so they are all shown on the map when loaded. Finally we set a little padding using pad(0.1) so there are no markers just on the borders of the map.

Image for post
Image for post
Galicia’s Unesco World Heritage sites.

When of the markers is selected, we set the center to its position and use the default zoom of 14.

The Custom Component

Our legend with the marker information will be a custom Leaflet Control.

Why a Control? Because it’s the only extendable element that it’s meant to be on our screen all the time and not positioned on the map or around a Marker.

We use an useEffect to add the control when our component is mounted. The control will be positioned to the bottomleft corner of the map and contain a div with the legend and its own styling (a pirate font seemed on point). We also have to define the required onAdd() method to return the HTMLElement that will fill the control. Note this is a string representation of a DOM element and not JSX.

All that is left it’s to be sure to clean up the control on unmount returning a function that calls its remove function.

But, but… you said to extend the appropriate React-Leaflet abstract component!

Yes! But while writing the example using React Hooks I found this way easier and more readable. Then I found Paul le Cam has a v3 on its way which changes the available hooks and the way of working with them. Maybe this was one of the reasons.

The previous “what component to extend from” list is still valid. Just use the wrapped original Leaflet component and you can extend them this way and use them on your React-Leaflet maps.

Now that we have our HeritageLegend component we can just use it in our map.

The HeritageLegend component inside our MyMap. Full example here.

After all that, we can click on any of our Markers and: Ahoy! The map will be centered around it, zoomed and its information will be shown like this:

Image for post
Image for post
Roman Walls of Lugo ahoy!

Summing up

As you can see it is possible to extend Leaflet controls to create your own and use them inside React-Leaflet.

There’s not a lot of documentation on using React-Leaflet with hooks. Its v2 docs just mentions the useLeaflet hook as we use it here, and there isn’t a lot of examples using it online, or combining it with React Hooks.

My recommendation would be to wait until v3 comes out, and meanwhile create your own components like this. It is not clear when will it be released, but you can follow the next branch on its Github repository.

Trabe

We are a development studio.

Lucas Andión

Written by

Galician. Software developer @trabe. Bike lover, beer enthusiast, mad traveler, beagle friend, surfer wannabe — https://andion.github.io

Trabe

Trabe

We are a development studio. We use Java, Rails, and JavaScript. This is where we write about the technologies we use at Trabe.

Lucas Andión

Written by

Galician. Software developer @trabe. Bike lover, beer enthusiast, mad traveler, beagle friend, surfer wannabe — https://andion.github.io

Trabe

Trabe

We are a development studio. We use Java, Rails, and JavaScript. This is where we write about the technologies we use at Trabe.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store