Creating a React-Leaflet Custom Component Using Hooks
How to Create your own Leaflet Components to use in your React Maps.
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.
To create your component, you will have to extend the appropriate abstract class from the ones exposed by React-Leaftlet.
You can extend:
Meant for controls, handles positioning.
Base class to handle adding and removing layers.
Base class that handles event bindings. Except
ControlledLayer, the rest of the base components inherit from this one. That includes the
Mapcomponent, the top-level component that instantiates a Leaflet map and provides it to its children.
Base class handling map panes. Panes are DOM elements used to control the ordering of layers on the map.
Base class extending
MapComponent, handles adding and removing the layer to the map when relevant. Exposes the layer in
For creating tile layers, handles
Handles shared logic for
MapLayerwith 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 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.
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.
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:
boundsprop: two geographical points defining a square that has to fit inside the map.
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.
When of the markers is selected, we set the center to its
position and use the default zoom of
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
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.
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:
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.