Integrating Google map and direction in React Native

NJI Darlington
6 min readMar 25, 2024

--

Integrating Google map and direction in React Native

Hello there! In this session, I will show you how to integrate Google Maps and Google Directions into your React Native application for free. This is a step-by-step, in-depth tutorial where we will go through setting up the dependencies and obtaining API keys for the project.

If you want to watch the video where I demonstrate how I accomplished this, check out my YouTube channel for the video (linked below). Please remember to Like and Subscribe.

First things first, we need to install the dependencies for our project. There are three libraries we used for this project:

  1. Expo Location (or any location library you prefer)
  2. React Native Maps
  3. React Native Maps Directions

To install these libraries, run the following command:

yarn add expo-location react-native-maps react-native-maps-directions

This command will install the libraries into your project using yarn. You can use any package manager of your choice, such as npm or pnpm.

Once the installation is complete, all you need to do is import the React Native Maps library and call it into your project. This will generate the map using Google as the provider, as shown below:

import MapView, { Marker } from 'react-native-maps';
<MapView
style={styles.map}
provider="google"
>
</MapView>

To ensure your map is visible, you need to apply specific styles to force the width and height of the map. You can customize these styles according to your preferences. However, remember to import Dimensions from react-native to avoid any errors. Here's how you can do it:

map: {
width: Dimensions.get('window').width,
height: Dimensions.get('window').height,
}

For a simple example, if you want your map to load with a default location, you need to add the initial location and the map zoom (latitudeDelta and longitudeDelta) in your MapView as attributes. Here’s how you can achieve this:

<MapView 
style={styles.map}
initialRegion={{
latitude: myLocation.latitude,
longitude: myLocation.longitude,
latitudeDelta: 0.0922,
longitudeDelta: 0.0721,
}}
provider="google"
>
</MapView>

In this example, myLocation is a state variable that holds the latitude and longitude coordinates. By default, it's initialized with the initialLocation coordinates. You can update myLocation state with your desired location as needed, and the map will be centered around that location. The latitudeDelta and longitudeDelta values determine the zoom level of the map. Adjust these values to control the initial zoom level of the map. Here is an example

const initialLocation = {latitude: 37.771707, longitude: -122.4053769};
const [myLocation, setMyLocation] = useState(initialLocation);

To integrate the location API and display the user’s position on the map, you can use the useEffect hook to request permission to access the user's location. Once permission is granted, you can retrieve the user's current position and update the myLocation state accordingly. Here's how you can do it:

import React, { useEffect, useState } from 'react';
import * as Location from 'expo-location';

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

const _getLocation = async () => {
try {
let { status } = await Location.requestForegroundPermissionsAsync();
if (status !== 'granted') {
console.log('Permission to access location was denied');
return;
}
let location = await Location.getCurrentPositionAsync({});
setMyLocation(location.coords);
} catch (err) {
console.warn(err);
}
};

From the above code, after requesting the user's location, we update the myLocation state using the setMyLocation to update the user's location.

This should set up everything for your application. Now to create a marker that will display the point and location, we need to add a Marker in the MapView and set the coordinates to the myLocation hook.

{ myLocation.latitude && myLocation.longitude &&
<Marker
coordinate={{
latitude: myLocation.latitude,
longitude: myLocation.longitude
}}
title='My current location'
description='I am here'
/>
}

We could also set a pin for the default location we created above using a “pin” useState

const [pin, setPin] = useState({})

const local = {
latitude: "37.78825",
longitude: "-122.4324"
}

useEffect(() => {
setPin(local)
_getLocation()
}, [])

Now to display the default pin we do it similarly to the myLocation marker above:

{ pin.latitude && pin.longitude &&
<Marker
coordinate={{
latitude: parseFloat(pin.latitude),
longitude: parseFloat(pin.longitude)
}}
title='Default location'
description='I am here'
/>
}

Remember these Markers go inside the MapView component created above. Your code should look like this:

return (
<MapView
style={styles.map}
initialRegion={{
latitude: myLocation.latitude,
longitude: myLocation.longitude,
latitudeDelta: 0.0922,
longitudeDelta: 0.0721,
}}
provider="google"
>

{ myLocation.latitude && myLocation.longitude &&
<Marker
coordinate={{
latitude: myLocation.latitude,
longitude: myLocation.longitude
}}
title='My current location'
description='I am here'
/>
}

{ pin.latitude && pin.longitude &&
<Marker
coordinate={{
latitude: parseFloat(pin.latitude),
longitude: parseFloat(pin.longitude)
}}
title='Default location'
description='I am here'
/>
}

</MapView>

)

To make our map a little more interesting, Let's add a button that will move the user to a new location so we can animate the process. So after our MapView let's add this code below and wrap the app in either an empty fragment or a View

<View style={styles.buttonContainer}>
<Button title='Get Location' onPress={focusOnLocation} />
</View>

buttonContainer: {
position: 'absolute',
bottom: 20,
width: '100%',
alignItems: 'center',
},

When the button is pressed, we want to run the function focusOnLocation which we will create here.

const focusOnLocation =() => {
if (myLocation.latitude && myLocation.longitude){
const newRegion = {
latitude: parseFloat(myLocation.latitude),
longitude: parseFloat(myLocation.longitude),
latitudeDelta: 0.0922,
longitudeDelta: 0.0421
}
if(mapRef.current){
mapRef.current.animateToRegion(newRegion, 1000)
}
}
}

Now back to our MapView, let's change some settings to make it animate to the new location and not just change. So update your mapView code thus:

<MapView
style={styles.map}
region={region}
onRegionChangeComplete={setRegion}
ref={mapRef}
provider='google'
>

Notice we added two variables and a function, mapRef is a ref you need to create in your function, while region and setRegion are hooks you should create below the ref as shown here.

const mapRef = useRef(null)
const [region, setRegion] = useState({
latitude: initialLocation.latitude,
longitude: initialLocation.longitude,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
});

And that should be everything you need to add a map to your application. For further customization, you can change the marker to display any image of your choice (perhaps your user's profile picture) by using the image property in the Marker element e.g image={require(‘/path/to/image.png’)

or create a custom Marker for your map

You can check out my video linked here where I show you how to create a custom maker and work you through this entire project.

In conclusion, your code for the map should look like this:

import { Button, Dimensions, StyleSheet, Text, View } from 'react-native'
import React, { useEffect, useRef, useState } from 'react'
import MapView, { Marker } from 'react-native-maps'
import * as Location from 'expo-location'
import CustomMarker from './CustomMarker'

export default function Map() {
const initialLocation = {
latitiude: 37.78825,
longitude: -122.4324,
}
const [myLocation, setMyLocation] = useState(initialLocation)
const [pin, setPin] = useState({})
const [region, setRegion] = useState({
latitude: initialLocation.latitude,
longitude: initialLocation.longitude,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
});
const mapRef = useRef(null)
const local = {
latitude: "37.78825",
longitude: "-122.4324"
}

useEffect(() => {
setPin(local)
_getLocation()
}, [])

const _getLocation =async() => {
try{
let { status } = await Location.requestForegroundPermissionsAsync()

if(status !== 'granted'){
console.warn('Permission to access location was denied')
return
}
let location = await Location.getCurrentPositionAsync({})
setMyLocation(location.coords)
console.log(location);
}
catch(err){
console.warn(err);
}
}

const focusOnLocation =() => {
if (myLocation.latitude && myLocation.longitude){
const newRegion = {
latitude: parseFloat(myLocation.latitude),
longitude: parseFloat(myLocation.longitude),
latitudeDelta: 0.0922,
longitudeDelta: 0.0421
}
if(mapRef.current){
mapRef.current.animateToRegion(newRegion, 1000)
}
}
}


return (
<View style={styles.container}>
<MapView
style={styles.map}
region={region}
onRegionChangeComplete={setRegion}
ref={mapRef}
provider='google'
>

{ myLocation.latitude && myLocation.longitude &&
<Marker
coordinate={{
latitude: myLocation.latitude,
longitude: myLocation.longitude
}}
title='My current location'
description='I am here'
/>
}

{ pin.latitude && pin.longitude &&
<Marker
coordinate={{
latitude: parseFloat(pin.latitude),
longitude: parseFloat(pin.longitude)
}}
title='Default location'
description='I am here'
/>
}

</MapView>
<View style={styles.buttonContainer}>
<Button title='Get Location' onPress={focusOnLocation} />
</View>
</View>
)
}

const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center'
},
map: {
width: Dimensions.get('window').width,
height: Dimensions.get('window').height,
},
buttonContainer: {
position: 'absolute',
bottom: 20,
width: '100%',
alignItems: 'center',
},
markerImage: {
width: 40,
height: 40,
borderRadius: 20,
}
})

A working code for this can be found in my GitHub and in case you didn’t understand the walk-through, check out my channel for the detailed explanation.

Thank you for reading to the end and I’ll see you next time ;)

You can refer to my Github repo for the full source code

--

--

NJI Darlington

I write content about software architecture, mobile design and algorithm. YouTube: @rising_tide