How to Draw Directions Route on a Map in React Native

Burcu
6 min readJan 30, 2024

--

Today, in React Native, we’re going to draw directions on a map showing the route between our current location and where we want to go.

First, let's create our project:

react-native init MapsApplication
cd MapsApplication
cd ios
pod install

Add react-native-maps library and install pods:

npm install react-native-maps
cd ios && pod install

To use google maps on Android you must get API key for the Android SDK.

When using Google Maps on iOS, you need also to obtain an API key for the iOS SDK and include the Google Maps library in your build.

Enabling Google Maps for IOS and Android

This step is explained very well here. Please complete it by following the steps here.

Do not forget to get permissions using the PermissionsAndroid API API in your Android app

After making the adjustments, let’s check if Google Maps is working by editing App.js:

import React from 'react';
import {View, StyleSheet} from 'react-native';
import MapView, {PROVIDER_GOOGLE} from 'react-native-maps';

const App = () => {
return (
<View style={styles.container}>
<MapView
provider={PROVIDER_GOOGLE}
style={styles.map}
region={{
latitude: 37.78825,
longitude: -122.4324,
latitudeDelta: 0.015,
longitudeDelta: 0.0121,
}}></MapView>
</View>
);
};
const styles = StyleSheet.create({
container: {
...StyleSheet.absoluteFillObject,
justifyContent: 'flex-end',
alignItems: 'center',
},
map: {
...StyleSheet.absoluteFillObject,
},
});

export default App;

Current location information via GPS

Let’s install react-native-geolocation library to get location information.

npm install @react-native-community/geolocation --save
cd ios && pod install

Configuration on iOS:

To enable geolocation when using the app, we need to add NSLocationWhenInUseUsageDescription and NSLocationAlwaysAndWhenInUseUsageDescription to Info.plist.

If your app supports iOS 10 and earlier, the NSLocationAlwaysUsageDescription key is also required

 <key>NSLocationWhenInUseUsageDescription</key>
<string>Do you allow the app to get your location?</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Do you allow the app to get your location?</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>Do you allow the app to get your location?</string>

In order to enable geolocation in the background, you need to include the ‘NSLocationAlwaysUsageDescription’ key in Info.plist and add location as a background mode in the ‘Capabilities’ tab in Xcode.

Configuration on Android:

To request access to location, you need to add the following line to your app’s AndroidManifest.xml:

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
or
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

Add the following codes to helper/helperFunction.js:

import Geolocation from '@react-native-community/geolocation';

export const getCurrentLocation = () =>
new Promise((resolve, reject) => {
Geolocation.getCurrentPosition(
position => {
const cords = {
latitude: position.coords.latitude,
longitude: position.coords.longitude,
heading: position?.coords?.heading,
};
resolve(cords);
},
error => {
reject(error.message);
},
{enableHighAccuracy: true, timeout: 15000, maximumAge: 10000},
);
});

App.js

import React, {useEffect, useRef, useState} from 'react';
import {StyleSheet, SafeAreaView, Dimensions} from 'react-native';
import MapView, {
PROVIDER_GOOGLE,
} from 'react-native-maps';
import {getCurrentLocation} from './helper/helperFunction';

const screen = Dimensions.get('window');
const ASPECT_RATIO = screen.width / screen.height;
const LATITUDE_DELTA = 0.04;
const LONGITUDE_DELTA = LATITUDE_DELTA * ASPECT_RATIO;

const App = () => {
const mapRef = useRef();
const [coord, setCoord] = useState();

const getLiveLocation = async () => {
const {latitude, longitude} = await getCurrentLocation();
setCoord({
latitude: latitude,
longitude: longitude,
latitudeDelta: LATITUDE_DELTA,
longitudeDelta: LONGITUDE_DELTA,
});
};

useEffect(() => {
getLiveLocation();
}, []);

return (
<SafeAreaView style={styles.container}>
<MapView
ref={mapRef}
provider={PROVIDER_GOOGLE}
style={styles.map}
initialRegion={coord}>
</MapView>
</SafeAreaView>
);
};

const styles = StyleSheet.create({
container: {
flex: 1,
},
map: {
...StyleSheet.absoluteFillObject,
zIndex: 0,
},
searchContainer: {
zIndex: 1,
flex: 0.5,
marginHorizontal: 10,
marginVertical: 5,
},
});

export default App;

When you run the app, the permission dialog will appear and when you give the permission, your location will appear on the map.

Add Marker

Let’s add a marker to the location obtained with Geolocation:

//...
import MapView, {
PROVIDER_GOOGLE,
Marker,
} from 'react-native-maps';

const App = () => {
//...

return (
<SafeAreaView style={styles.container}>
<MapView
ref={mapRef}
provider={PROVIDER_GOOGLE}
style={styles.map}
initialRegion={coord}>
{coord !== undefined && (
<Marker coordinate={coord}/>
)}
</MapView>
</SafeAreaView>
);
};

Using Google Places Autocomplete

npm install react-native-google-places-autocomplete --save
import React, {useEffect, useRef, useState} from 'react';
import {View, StyleSheet, Text, SafeAreaView, Dimensions} from 'react-native';
import MapView, {PROVIDER_GOOGLE, Marker} from 'react-native-maps';
import {GooglePlacesAutocomplete} from 'react-native-google-places-autocomplete';
import {GOOGLE_PLACES_API_KEY} from './constants/GooglePlacesAPIKey';
import {getCurrentLocation} from './helper/helperFunction';

const screen = Dimensions.get('window');
const ASPECT_RATIO = screen.width / screen.height;
const LATITUDE_DELTA = 0.04;
const LONGITUDE_DELTA = LATITUDE_DELTA * ASPECT_RATIO;

const App = () => {
const mapRef = useRef();
const [coord, setCoord] = useState();

const getLiveLocation = async () => {
const {latitude, longitude} = await getCurrentLocation();
setCoord({
latitude: latitude,
longitude: longitude,
latitudeDelta: LATITUDE_DELTA,
longitudeDelta: LONGITUDE_DELTA,
});
};

useEffect(() => {
getLiveLocation();
}, []);

return (
<SafeAreaView style={styles.container}>
<View style={styles.searchContainer}>
<GooglePlacesAutocomplete
placeholder="Search"
fetchDetails={true}
onPress={(data, details = null) => {
// 'details' is provided when fetchDetails = true
}}
query={{
key: GOOGLE_PLACES_API_KEY,
language: 'en',
}}
/>
</View>
<MapView
ref={mapRef}
provider={PROVIDER_GOOGLE}
style={styles.map}
initialRegion={coord}>
{coord !== undefined && (
<Marker coordinate={coord}/>
)}
</MapView>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
},
map: {
...StyleSheet.absoluteFillObject,
zIndex: 0,
},
searchContainer: {
zIndex: 1,
flex: 0.5,
marginHorizontal: 10,
marginVertical: 5,
},
});

export default App;

Let’s update the destination coordinates according to the selected address and show the destination coordinate with a marker:

const App = () => {
//...
const [destination, setDestination] = useState();

const onPressAddress = details => {
setDestination({
latitude: details?.geometry?.location.lat,
longitude: details?.geometry?.location.lng,
});
moveToLocation(
details?.geometry?.location.lat,
details?.geometry?.location.lng,
);
};

const moveToLocation = async (latitude, longitude) => {
mapRef.current.animateToRegion(
{
latitude,
longitude,
latitudeDelta: LATITUDE_DELTA,
longitudeDelta: LONGITUDE_DELTA,
},
2000,
);
};

return (
<SafeAreaView style={styles.container}>
<View style={styles.searchContainer}>
<GooglePlacesAutocomplete
placeholder="Search"
fetchDetails={true}
onPress={(data, details = null) => {
// 'details' is provided when fetchDetails = true
onPressAddress(details);
}}
query={{
key: GOOGLE_PLACES_API_KEY,
language: 'en',
}}
/>
</View>
<MapView
ref={mapRef}
provider={PROVIDER_GOOGLE}
style={styles.map}
initialRegion={coord}>
{coord !== undefined && (
<Marker coordinate={coord}/>
)}
{destination !== undefined && (
<Marker coordinate={destination}/>
)}
</SafeAreaView>
)

}

Now we can obtain the current position and the position of the destination and show it on the map. Now we will draw directions with react-native-maps-directions.

npm install react-native-maps-directions

App.js:

import React, {useEffect, useRef, useState} from 'react';
import {View, StyleSheet, Text, SafeAreaView, Dimensions} from 'react-native';
import MapView, {PROVIDER_GOOGLE, Marker} from 'react-native-maps';
import {GooglePlacesAutocomplete} from 'react-native-google-places-autocomplete';
import MapViewDirections from 'react-native-maps-directions';
import {GOOGLE_PLACES_API_KEY} from './constants/GooglePlacesAPIKey';
import {getCurrentLocation} from './helper/helperFunction';

const screen = Dimensions.get('window');
const ASPECT_RATIO = screen.width / screen.height;
const LATITUDE_DELTA = 0.04;
const LONGITUDE_DELTA = LATITUDE_DELTA * ASPECT_RATIO;

const App = () => {
const mapRef = useRef();
const [coord, setCoord] = useState();
const [destination, setDestination] = useState();

const onPressAddress = details => {
setDestination({
latitude: details?.geometry?.location.lat,
longitude: details?.geometry?.location.lng,
});
moveToLocation(
details?.geometry?.location.lat,
details?.geometry?.location.lng,
);
};

const moveToLocation = async (latitude, longitude) => {
mapRef.current.animateToRegion(
{
latitude,
longitude,
latitudeDelta: LATITUDE_DELTA,
longitudeDelta: LONGITUDE_DELTA,
},
2000,
);
};

const getLiveLocation = async () => {
const {latitude, longitude} = await getCurrentLocation();
setCoord({
latitude: latitude,
longitude: longitude,
latitudeDelta: LATITUDE_DELTA,
longitudeDelta: LONGITUDE_DELTA,
});
};

useEffect(() => {
getLiveLocation();
}, []);

return (
<SafeAreaView style={styles.container}>
<View style={styles.searchContainer}>
<GooglePlacesAutocomplete
placeholder="Search"
fetchDetails={true}
onPress={(data, details = null) => {
// 'details' is provided when fetchDetails = true
onPressAddress(details);
}}
query={{
key: GOOGLE_PLACES_API_KEY,
language: 'en',
}}
/>
</View>
<MapView
ref={mapRef}
provider={PROVIDER_GOOGLE}
style={styles.map}
initialRegion={coord}>
{coord !== undefined && (
<Marker coordinate={coord}/>
)}
{destination !== undefined && (
<Marker coordinate={destination}/>
)}
{coord != undefined && destination != undefined ? (
<MapViewDirections
origin={coord}
destination={destination}
apikey={GOOGLE_PLACES_API_KEY}
strokeColor="hotpink"
strokeWidth={4}
/>
) : null}
</MapView>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
},
map: {
...StyleSheet.absoluteFillObject,
zIndex: 0,
},
searchContainer: {
zIndex: 1,
flex: 0.5,
marginHorizontal: 10,
marginVertical: 5,
},
});

export default App;

In React Native, we were able to draw a route for directions between two given locations on a map.

You can find the finished project in the react-native-maps-application rep.

Thank you for reading!

--

--