Written by Gaurav Singhal✏️
Having accurate information about your users’ location is a great way to enhance the user experience. For example, you could use this data to show users what is around them, offer exclusive deals for products and services in their area, and much more. Fortunately, if you have a React application, implementing maps is a breeze using the react-native-maps
library.
react-native-maps
is a component system for maps that ships with platform-native code that needs to be compiled together with React Native. In this guide, we’ll demonstrate how to integrate Google Maps into your React Native application and introduce you to fundamental components such as <MapView />
and <Marker>
.
Let’s get started!
Installation
The first thing you need to do is obtain the API key for configuring Google Maps on Android. Once you have the API key, include it in your AndroidManifest.xml
file as the child of the <application>
element.
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="YOUR_API_KEY"/>
Next, run the following command to install react-native-maps
in your project.
yarn add react-native-maps -E
Basic use
Remove all the default code from the App.js
file and import the <MapView />
component from react-native-maps
.
import MapView from "react-native-maps";
Inside the component, render the <MapView />
component.
import React from "react";
import MapView from "react-native-maps";
const App = () => {
return (
<MapView
style={{ flex: 1 }}
initialRegion={{
latitude: 37.78825,
longitude: -122.4324,
latitudeDelta: 0.05,
longitudeDelta: 0.05
}}
/>
);
};
export default App;
The initialRegion
prop shows the region that is to be displayed on the map when the component mounts. The initialRegion
value cannot be changed after it has been initialized. Don’t forget to add the style property to specify the dimensions. Otherwise, you’ll end up with a white screen. The value { flex: 1 }
will ensure that the <MapView />
takes up the entire screen.
You’ll need to pass an object with the latitude, longitude, and delta values of a region to the initialRegion
prop. The latitudeDelta
and longitudeDelta
properties specify how much the area on the map must be zoomed. To change the region, use the region
prop.
Using react-native-maps
with the useState
hook
To change the region with the state hook, use the onRegionChangeComplete
prop to set the new region into the state. The onRegionChangeComplete
is a callback prop that is called only once when the region changes.
import React, { useState } from "react";
import MapView from "react-native-maps";
const App = () => {
const [region, setRegion] = useState({
latitude: 51.5079145,
longitude: -0.0899163,
latitudeDelta: 0.01,
longitudeDelta: 0.01
});
return (
<MapView
style={{ flex: 1 }}
region={region}
onRegionChangeComplete={region => setRegion(region)}
/>
);
};
export default App;
Displaying markers on the map
Start by importing Marker
from react-native-maps
.
import MapView, { Marker } from "react-native-maps";
Next, render the <Marker />
component as a child of <MapView />
. Pass the coordinate for the marker in the coordinate
prop.
import React, { useState } from "react";
import MapView, { Marker } from "react-native-maps";
const App = () => {
const [region, setRegion] = useState({
latitude: 51.5078788,
longitude: -0.0877321,
latitudeDelta: 0.009,
longitudeDelta: 0.009
});
return (
<MapView
style={{ flex: 1 }}
region={region}
onRegionChangeComplete={region => setRegion(region)}
>
<Marker coordinate={{ latitude: 51.5078788, longitude: -0.0877321 }} />
</MapView>
);
};
export default App;
The marker should be visible, as shown below.
You can add n
number of markers to the map and pass it as a direct child to the <MapView />
component.
Custom marker color
To change the color of the marker, use the pinColor
prop.
<Marker
coordinate={{ latitude: 52.5200066, longitude: 13.404954 }}
pinColor="green"
/>
Custom marker image
You can also add a custom marker image by passing the image
prop to the <Marker />
component.
<Marker
coordinate={{ latitude: 52.5200066, longitude: 13.404954 }}
image={require("./car.png")}
/>
Custom marker view
The following will display a location with a custom marker view component.
import React, { useState } from "react";
import { View, Text } from "react-native";
import MapView, { Marker } from "react-native-maps";
const CustomMarker = () => (
<View
style={{
paddingVertical: 10,
paddingHorizontal: 30,
backgroundColor: "#007bff",
borderColor: "#eee",
borderRadius: 5,
elevation: 10
}}
>
<Text style={{ color: "#fff" }}>Berlin</Text>
</View>
);
const App = () => {
const [region, setRegion] = useState({
latitude: 52.5200066,
longitude: 13.404954,
latitudeDelta: 0.005,
longitudeDelta: 0.005
});
return (
<MapView
style={{ flex: 1 }}
region={region}
onRegionChangeComplete={region => setRegion(region)}
>
<Marker coordinate={{ latitude: 52.5200066, longitude: 13.404954 }}>
<CustomMarker />
</Marker>
</MapView>
);
};
export default App;
Styling the map
Generate the JSON object you’ll use to design the map from the Google style generator.
Next, pass the generated style object to the customMapStyle
prop of the <MapView />
component.
import React, { useState } from "react";
import { View, Text } from "react-native";
import MapView, { Marker } from "react-native-maps";
const mapStyle = [
{
elementType: "geometry",
stylers: [
{
color: "#1d2c4d"
}
]
},
{
elementType: "labels.text.fill",
stylers: [
{
color: "#8ec3b9"
}
]
},
// ...
{
featureType: "water",
elementType: "geometry.fill",
stylers: [
{
color: "#3e73fd"
}
]
},
{
featureType: "water",
elementType: "labels.text.fill",
stylers: [
{
color: "#4e6d70"
}
]
}
];
const CustomMarker = () => (
<View
style={{
paddingVertical: 10,
paddingHorizontal: 30,
backgroundColor: "#fff",
borderColor: "#eee",
borderRadius: 5,
elevation: 10
}}
>
<Text>Berlin</Text>
</View>
);
const App = () => {
const [region, setRegion] = useState({
latitude: 52.5200066,
longitude: 13.404954,
latitudeDelta: 0.005,
longitudeDelta: 0.005
});
return (
<MapView
style={{ flex: 1 }}
region={region}
onRegionChangeComplete={region => setRegion(region)}
customMapStyle={mapStyle}
>
<Marker coordinate={{ latitude: 52.5200066, longitude: 13.404954 }}>
<CustomMarker />
</Marker>
</MapView>
);
};
export default App;
You can ignore the mapStyle
variable. Since it will be generated from the map style generator, you only need to paste the JSON object into your code and send it to the <MapView />
component.
As you can see, the map style changed from the default light theme to a customized dark theme.
Animating to a coordinate
What if you want to animate to a particular coordinate?
First, create a ref to <MapView />
using the useRef()
hook.
import React, { useState, useRef, useEffect } from "react";
import { View, Text } from "react-native";
import MapView, { Marker } from "react-native-maps";
// ...
const App = () => {
const _map = useRef(null);
useEffect(() => {
// ...
}, []);
return (
<>
<MapView
style={{ flex: 1 }}
ref={_map}
initialRegion={{
latitude: 52.5200066,
longitude: 13.404954,
latitudeDelta: 0.1,
longitudeDelta: 0.1
}}
>
<Marker coordinate={{ latitude: 52.5200066, longitude: 13.404954 }}>
<CustomMarker />
</Marker>
</MapView>
</>
);
};
export default App;
Next, inside the useEffect()
hook, use the animateCamera()
function to animate the MapView
region.
useEffect(() => {
if(_map.current) {
_map.current.animateCamera(
{
center: {
latitude: 50.1109221,
longitude: 8.6821267
}
zoom: 15
},
5000
);
}
}, []);
The useRef()
hook returns a mutable ref object whose current
property has the value of the passed argument. If the value of current
property is undefined
, that means the component is not yet mounted. Now you can access any of the <MapView />
methods using _map.current
.
The animateCamera()
method accepts an object with center
, zoom
, heading
, and altitude
properties as its argument and the animation duration in milliseconds. You can pass the region’s latitude and longitude in the center
property, but unlike the initialRegion
prop, you cannot give the delta values. The zoom
property specifies the extent to which the region needs to be zoomed.
Adding a line to the map
You can use the <Polyline />
component from the react-native-maps
library to create lines between multiple coordinates. It accepts an array of coordinates in its coordinates
prop. You can also specify additional props for styling purposes, such as strokeWidth
, strokeColor
, etc.
Let’s create a path between Berlin and Frankfurt.
import React from "react";
import MapView, { Polyline } from "react-native-maps";
const App = () => {
const Berlin = {
latitude: 52.5200066,
longitude: 13.404954
};
const Frankfurt = {
latitude: 50.1109221,
longitude: 8.6821267
};
return (
<>
<MapView
style={{ flex: 1 }}
initialRegion={{
latitude: 52.5200066,
longitude: 13.404954,
latitudeDelta: 0.1,
longitudeDelta: 0.1
}}
>
<Polyline coordinates={[Berlin, Franfurt]} />
</MapView>
</>
);
};
export default App;
Store the coordinates for the locations in their respective variables and pass them in an array to the coordinates
prop of the <Polyline />
component.
If you look at the results, the line is drawn directly between these coordinates and does not take into account the actual geographical paths and roads. For that, you’ll need to establish multiple coordinates between the source and destination locations by using the Google Maps Direction API, which returns all possible routes between two places.
Create a getDirections
function that accepts the coordinates in string format.
const getDirections = async (startLoc, destinationLoc) => {
try {
const KEY = "YOUR GOOGLE API KEY";
let resp = await fetch(
`https://maps.googleapis.com/maps/api/directions/json?origin=${startLoc}&destination=${destinationLoc}&key=${KEY}`
);
let respJson = await resp.json();
let points = decode(respJson.routes[0].overview_polyline.points);
console.log(points);
let coords = points.map((point, index) => {
return {
latitude: point[0],
longitude: point[1]
};
});
return coords;
} catch (error) {
return error;
}
};
Import the decode()
function from the @mapbox/polyline
library.
import { decode } from "@mapbox/polyline";
The decode()
function will convert the encoded polyline points from the overview_polyline.points
property into an array containing the latitude and longitude of all the coordinates.
import React, { useState, useEffect } from "react";
import { View, Text } from "react-native";
import MapView, { Polyline } from "react-native-maps";
import { decode } from "@mapbox/polyline";
const getDirections = async (startLoc, destinationLoc) => {
try {
const KEY = "YOUR GOOGLE API KEY";
let resp = await fetch(
`https://maps.googleapis.com/maps/api/directions/json?origin=${startLoc}&destination=${destinationLoc}&key=${KEY}`
);
let respJson = await resp.json();
let points = decode(respJson.routes[0].overview_polyline.points);
let coords = points.map((point, index) => {
return {
latitude: point[0],
longitude: point[1]
};
});
return coords;
} catch (error) {
return error;
}
};
const App = () => {
const [coords, setCoords] = useState([]);
useEffect(() => {
getDirections("52.5200066,13.404954", "50.1109221,8.6821267")
.then(coords => setCoords(coords))
.catch(err => console.log("Something went wrong"));
}, []);
return (
<>
<MapView
style={{ flex: 1 }}
initialRegion={{
latitude: 52.5200066,
longitude: 13.404954,
latitudeDelta: 0.1,
longitudeDelta: 0.1
}}
>
{coords.length > 0 && <Polyline coordinates={coords} />}
</MapView>
</>
);
};
export default App;
Conclusion
You should now have a basic understanding of how to implement maps, their benefits, and how to build features on top of the react-native-maps
library. You can implement these lessons into your work to build myriad types of applications, from taxi services, to restaurant finders, to delivery apps, and much more. The react-native-maps
library makes it simple to integrate maps and is an essential player in the React Native ecosystem.
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 — start monitoring for free.
The post Introduction to react-native-maps appeared first on LogRocket Blog.
Top comments (0)