Introduction
Usually developers struggle with issues like how to embed maps in app, how to show data on map, etc. With this article, we will learn how to display API data on map in react application using leaflet
& react-leaflet
.
We will observe how based on user’s clicking anywhere on the map, coordinates (latitude and longitude) will be recorded and sent as parameters to API and then data (like nearby cities) gets fetched and displayed on the map.
Prerequisites
We need to have fair knowledge of how React works.
Why Leaflet & React-Leaflet ?
Leaflet is an open source JS library to work with interactive maps. It lets us add markers, circles, polygons, show dynamic data based on users' interactions.
React-Leaflet is a package acting as bridge between React and Leaflet. It provides useful components, hooks like MapComponent
, TileLayer
, Marker
, useMap
, useMapEvents
, etc. helping users to deal with map interactivity.
Rapid API Subscription
To consume API, we have to create an account on Rapid API . Then, search for booking com:
Before using this api, we need to login/sign up and subscribe to it. Once subscribed, we will find Subscribed on the right side as shown in the above image. Finally, we are ready to consume api.
For this article, you will use Nearby Cities
endpoint:
We will choose Javascript (Axios) to get the code for testing the endpoint.
X-RapidAPI-Key is secret key accessible for the subscribed users only. So, please don't share it with others.
Latitude, longitude and locale are mandatory parameters that needs to be passed as params while testing the api endpoint.
Installations
Once you have the above mentioned code snippet with required parameters, move to the next step for creating React app named mapData.
With the following commands, we'll have our react app up and running at http://localhost:3000.
1. npx create-react-app mapData
2. cd mapData
3. npm start
To embed maps in react app, you need to install following package:
npm install leaflet react-leaflet axios
Project Structure
Once done with installations, let’s start writing code -
Project Structure will look like this:
Add Leaflet CSS
In index.html
under public
folder, write following code inside <head>
tag to include Leaflet CSS
file:
<link
rel="stylesheet"
href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css"
integrity="sha256-kLaT2GOSpHechhsozzB+flnD+zUyjE2LlfWPgU04xyI="
crossorigin=""
/>
- Add following css in
src/components/map/index.css
which must have leaflet-container as the classname for the visibility of map:
.leaflet-container {
width: 100vw;
height: 100vh;
}
Consume booking com api
Write the following code in src/api/index.js
:
import axios from "axios";
export const getNearbyCities = async(coordinates) => {
// console.log("coordinates ", coordinates)
const {lat, lng} = coordinates;
const options = {
method: 'GET',
url: 'https://booking-com.p.rapidapi.com/v1/hotels/nearby-cities',
params: {
latitude: lat,
longitude: lng,
locale: 'en-gb'
},
headers: {
'X-RapidAPI-Key': 'YOUR_SECRET_API_KEY',
'X-RapidAPI-Host': 'booking-com.p.rapidapi.com'
}
};
try {
const response = await axios.request(options);
console.log("cities ", response.data);
return response.data;
} catch (error) {
console.error(error);
}
}
In this code,
-
getNearbyCities
accepts coordinates as parameter and coordinates value changes whenever user clicks anywhere on the map. -
url in
options
uses/hotels/nearby-cities
as the endpoint. - params contain latitude, longitude and locale
- headers contain X-RapidAPI-Key & X-RapidAPI-Host
Displaying API Data on map
Write following code in src/components/map/index.js
:
import React, { useEffect, useState } from 'react'
import { MapContainer, TileLayer, Marker, Popup, useMapEvent } from 'react-leaflet';
import './index.css'; // Very important as it loads Leaflet's CSS
import { Icon } from 'leaflet';
import { getNearbyCities } from '../../api';
// to use any marker, use following method -
const redIcon = new Icon({
iconUrl: require('../../img/redMarker.webp'), // path where red marker icon is located
iconSize: [40, 40]
})
const Map = () => {
const [marker, setMarker] = useState({lat: 51.505, lng: -0.09}) // initial coordinates of blue marker when app renders
const [citiesLocation, setCitiesLocation] = useState([]) // it contains locations of nearby-cities
// fetched by api
function SetViewOnClick() {
const map = useMapEvent('click', (e) => {
console.log("click event info => ", e)
setMarker(e.latlng); // to update the location of blue Marker
map.setView(e.latlng, map.getZoom())
})
return null;
}
useEffect(() => {
console.log("e.latlng ",marker)
getNearbyCities(marker) // passing marker as coordinates to fetch nearby-cities' locations
.then(data => setCitiesLocation(data))
.catch(err => console.log(err));
},[marker])
return (
<MapContainer
center={marker}
zoom={12}
scrollWheelZoom={true}
>
<TileLayer
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<Marker position={marker}>
<Popup>
See this
</Popup>
</Marker>
{
citiesLocation?.map((item, index) => ( // at each city location, redIconed marker will be visible
<Marker key={index} icon={redIcon} position={[item.latitude, item.longitude]}>
<Popup>
{item.name}, {item.country}
</Popup>
</Marker>
))
}
<SetViewOnClick />
</MapContainer>
)
}
export default Map;
In the above code,
-
const [marker, setMarker] = useState({lat: 51.505, lng: -0.09})
indicates initial coordinates of blue marker (check in Output section) when app renders -
const [citiesLocation, setCitiesLocation] = useState([])
will contain locations of nearby-cities fetched by api -
function SetViewOnClick()
updates the location of blue marker based on user's click as well as view just by clicking on the map. -
map.setView(e.latlng, map.getZoom())
sets the view of the map to the location where clicked and zooms -
useEffect(() => { ... },[marker])
have dependency array containing marker, It means on changing marker's value, useEffect will trigger,getNearbyCities
executes and populatescitiesLocation
-
<MapContainer center={marker} zoom={12} scrollWheelZoom={true}>...</MapContainer>
has center showing the center of the map, zoom showing zoom level and scrollWheelZoom to decide whether map can be zoomed using mouse scroll wheel. -
<TileLayer attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" />
We need to add Tile layer to our map, in our case it's OpenStreetMap tile layer and it requires anattribution
. Thereafter, map loads. -
<Marker position={marker}> <Popup> See this </Popup> </Marker>
shows the marker with the popup (when clicked)
Rendering of Map inside src/App.js
import React from 'react';
import './App.css';
import Map from './components/map';
function App() {
return (
<div className="App">
<Map/> {/** Map component will contain the map shown in our React app */}
</div>
);
}
export default App;
And, then <App/>
inside src/index.js
:
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<div>
<App />
</div>
);
Output
Final output -
On rendering, map shows following data:
- Blue marker shows coordinates(
lat: 51.505, lng: -0.09
) ofSouthwark London England United Kingdom
. - Red markers show cities' locations nearby
London, UK
.
Check the console tab in developer console after rendering:
After clicking anywhere on the map, blue marker's position gets updated and accordingly, cities' locations update.
Check out following image:
Check the console tab in developer console after clicking:
Popups with location names
Conclusion
With this article, now you would be able to embed maps in react app and play around with it as per your requirements.
References
https://leafletjs.com/examples/quick-start/
https://react-leaflet.js.org/docs/start-setup/
Top comments (0)