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:
- Expo Location (or any location library you prefer)
- React Native Maps
- 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