Google Auto Complete React Native Maps using React Native
By: Prateek Chitransh
Tags: Google Autocompletes, Google Map Api, Maps, React Native Maps, React Native

How to use Google Autocomplete Search API and React Native Maps in React Native to fetch user location ? Prateek Chitransh Follow Aug 23, 2020 · 7 min read

Today we will be making an Ola/Uber like address component where you can fetch a users location in three ways :

By using Google-AutoComplete Search API By Dragging a google map around a centred marker By text input entered by the user

Our aim is to have a screen which looks like this :

Google Auto Complete Search

If you are looking for a quick solution this will be really helpful and I hope you achieve more than what I am offering you using the process I followed.

Wear your anti glare glasses and let’s begin !

Step 1 : Install react-native-maps

npm install react-native-maps

The version I used at the time of publishing was 0.26.1. If you wish to install the same version so that there is no version mismatch try :

npm install react-native-maps@0.26.1

Step 2 : Install react-native-google-places-autocomplete

npm install react-native-google-places-autocomplete

The version I used is 1.4.0.

Now in your project folder create a file : AddAddress.tsx ( You can go ahead with any name or extension as per the guidelines in your project. You might have to format the code at some points if you are using Javascript. )

AddAddress.tsx

import React from "react"; import {View,StyleSheet} from "react-native"; import MapView from "react-native-maps"; import { GooglePlacesAutocomplete } from "react-native-google-places-autocomplete"; export default class LocationPickerDemo extends React.Component<any, any> {

render(){

(<View>

</View>);

}

} const styles = StyleSheet.create({});

This is how your initial file should look like. As you can see we have imported both our libraries react-native-maps and react-native-google-places-autocomplete already to use their functionalities. MapView will help us to render the map and GooglePlacesAutocomplete will give us the search bar at top as you can see in the image. We have created a custom stylesheet as well in our component which we will be populating soon.

Next we are going to implement the map on the screen for starting off with the Google API integrations in your react native app :

AddAddress.tsx

import React from "react"; import {View,StyleSheet} from "react-native"; import MapView from "react-native-maps"; import { GooglePlacesAutocomplete } from "react-native-google-places-autocomplete"; const latitudeDelta = 0.025;

const longitudeDelta = 0.025; export default class LocationPickerDemo extends React.Component<any, any> { state = {

region: {

latitudeDelta,

longitudeDelta,

latitude: 12.840575,

longitude: 77.651787,

}

} render(){

<View style={styles.map}>

<MapView

style={styles.map}

initialRegion={this.state.region}

/>

</View>}

} const styles = StyleSheet.create({

map:{

flex:1

},

});

Next we will keep our fetch Address API ready and integrate our GOOGLE API KEY with the search API.

AddAddress.tsx

import React from "react"; import {View,StyleSheet} from "react-native"; import MapView from "react-native-maps"; import { GooglePlacesAutocomplete } from "react-native-google-places-autocomplete"; const latitudeDelta = 0.025;

const longitudeDelta = 0.025; export default class LocationPickerDemo extends React.Component<any, any> { state = {

region: {

latitudeDelta,

longitudeDelta,

latitude: 12.840575,

longitude: 77.651787,

}

} getAddress(){

//function to get address using current lat and lng fetch("https://maps.googleapis.com/maps/api/geocode/json?address=" + this.state.region.latitude+"," +this.state.region.longitude +"&key=" + <YOUR_GOOGLE_API_KEY>).then((response) => response.json()).then((responseJson) => {

console.log("ADDRESS GEOCODE is BACK!! => " +

JSON.stringify(responseJson));

this.setState(

{ address: JSON.stringify(responseJson.results[0].formatted_address)

.replace(/"/g, "")

});

});

} render(){

<View style={styles.map}>

<MapView

style={styles.map}

initialRegion={this.state.region}

/>

</View>}

} const styles = StyleSheet.create({

map:{

flex:1

},

});

The getAddress() function returns the value of an address that we receive as a result of the geocode api call we have made inside the function passing your key and coordinates. Next we will introduce the TextInput address in our component.

import React from "react"; import {View, Image,TouchableOpacity,TextInput,KeyboardAvoidingView,Text} from "react-native"; import { Icon } from 'react-native-elements'; import MapView from "react-native-maps"; import { GooglePlacesAutocomplete } from "react-native-google-places-autocomplete"; const latitudeDelta = 0.025;

const longitudeDelta = 0.025; export default class AddressPicker extends React.Component<any, any> { state = {

region: {

latitudeDelta,

longitudeDelta,

latitude: 12.840575,

longitude: 77.651787,

},

address:""

} getAddress(){

//function to get address using current lat and lng fetch("https://maps.googleapis.com/maps/api/geocode/json?address=" + this.state.region.latitude+"," +this.state.region.longitude +"&key=" + <YOUR_GOOGLE_API_KEY>).then((response) => response.json()).then((responseJson) => {

console.log("ADDRESS GEOCODE is BACK!! => " +

JSON.stringify(responseJson));

this.setState(

{ address: JSON.stringify(responseJson.results[0].formatted_address)

.replace(/"/g, "")

});

});

} render(){

<View style={styles.map}>

<MapView

style={styles.map}

initialRegion={this.state.region}

/> //Added a custom marker at the center of screen

<View style={styles.markerFixed}>

<Image

style={styles.marker}

source={require("../../assets/marker.png")}/>

</View> //Created A Footer Panel to show/enter address

<KeyboardAvoidingView style={styles.footer}>

<View style={{ flexDirection: "row", margin: 10 }}>

<Icon name="ios-home"

size={24}

color="#000000"

type="ionicon"

style={{

padding: 10,

}}

/>

<Text style={styles.addressText}>Address</Text>

</View>

<TextInput

multiline={true}

clearButtonMode="while-editing"

style={{

marginBottom: 5,

width: "90%",

minHeight: 70,

alignSelf: "center",

borderColor: "lightgrey",

borderWidth: 1.5,

fontSize: 12,

borderRadius: 5,

flex: 0.5,

alignContent: "flex-start",

textAlignVertical: "top",

fontFamily: "Calibri",

}}

onChangeText={(text) =>this.setState({ address: text })}

value={this.state.address}

/>

<TouchableOpacity

onPress={() => {}}

style={{

width: "30%",

alignSelf: "center",

alignItems: "center",

backgroundColor: "blue",

borderRadius: 16.5,

shadowColor: "rgba(0,0,0, .4)", // IOS

shadowOffset: { height: 1, width: 1 }, // IOS

shadowOpacity: 1, // IOS

shadowRadius: 1, //IOS

elevation: 2, // Android

}}>

<Text

style={{

color: "white"

fontFamily: "Calibri",

fontSize: 12,

paddingVertical: 4,

}}>

SAVE

</Text>

</TouchableOpacity>

</KeyboardAvoidingView>

</View>

}

} const styles = StyleSheet.create({

map:{

flex:1

},

markerFixed: {

left: "50%",

marginLeft: -24,

marginTop: -48,

position: "absolute",

top: "50%",

},

addressText: {

color: "black",

margin: 3,

fontFamily: "Calibri",

},

footer: {

backgroundColor: "white",

bottom: 0,

position: "absolute",

width: "100%",

height: "30%",

},

});

Now if you run your app you will be able to see the Map with a marker in the center of the screen and the address field at the bottom of the screen. Now lets implement the GoogleAutoComplete feature and finish off rest of the functionalities.

Note : You will have to edit the below file as per your requirements and install the missing components/remove add necessary tags.

import React from "react"; import {Image,StyleSheet,Text,View,TextInput,TouchableOpacity,

KeyboardAvoidingView} from "react-native"; import MapView from "react-native-maps"; import { GooglePlacesAutocomplete } from "react-native-google-places-autocomplete"; const latitudeDelta = 0.025;

const longitudeDelta = 0.025; export default class LocationPickerDemo extends React.Component<any, any> { searchText: any;

mapView: any;

state = {

region: {

latitudeDelta,

longitudeDelta,

latitude: 12.840575,

longitude: 77.651787,

},

listViewDisplayed: true,

address: "",

showAddress: false,

search: "",

currentLat: "",

currentLng: "",

forceRefresh: 0,

}; goToInitialLocation = (region) => {

let initialRegion = Object.assign({}, region);

initialRegion["latitudeDelta"] = 0.005;

initialRegion["longitudeDelta"] = 0.005;

this.mapView.animateToRegion(initialRegion, 2000);

}; onRegionChange = (region) => {

this.setState({

region: region,

forceRefresh: Math.floor(Math.random() * 100),

},

this.getCurrentAddress//callback

);

}; componentWillMount() {

this.getCurrentAddress();

} getAddress({

fetch("https://maps.googleapis.com/maps/api/geocode/json? address=" + this.state.region.latitude+"," +this.state.region.longitude +"&key=" + <YOUR_GOOGLE_API_KEY>).then((response) => response.json()).then((responseJson) => {

console.log("ADDRESS GEOCODE is BACK!! => " +

JSON.stringify(responseJson));

this.setState(

{ address: JSON.stringify(responseJson.results[0].formatted_address)

.replace(/"/g, "")

});

});

} render() {

const { region } = this.state;



return (

<View style={styles.map}>

<MapView

ref={(ref) => (this.mapView = ref)}

onMapReady={() =>

this.goToInitialLocation(this.state.region)}

style={styles.map}

initialRegion={this.state.region}

onRegionChangeComplete={this.onRegionChange}

/> <View style={styles.panel}>

<View style={[styles.panelHeader,

this.state.listViewDisplayed? styles.panelFill:styles.panel,]}>. <GooglePlacesAutocomplete

currentLocation={false}

enableHighAccuracyLocation={true}

ref={(c) => (this.searchText = c)}

placeholder="Search for a location"

minLength={2} // minimum length of text to search

autoFocus={false}

returnKeyType={"search"}

listViewDisplayed={this.state.listViewDisplayed}

fetchDetails={true}

renderDescription={(row) => row.description}

enablePoweredByContainer={false}

listUnderlayColor="lightgrey"

onPress={(data, details) => {

this.setState({

listViewDisplayed: false,

address: data.description,

currentLat: details.geometry.location.lat,

currentLng: details.geometry.location.lng,

region: {

latitudeDelta,

longitudeDelta,

latitude: details.geometry.location.lat,

longitude:details.geometry.location.lng,

},

});

this.searchText.setAddressText("");

this.goToInitialLocation(this.state.region);}}

textInputProps={{

onChangeText: (text) => {

console.log(text);

this.setState({listViewDisplayed: true});

},

}}

getDefaultValue={() => {

return ""; // text input default value

}}

query={{

key: "<YOUR_API_KEY>",

language: "en", // language of the results

components: "country:ind",

}}

styles={{

description: {

fontFamily: "Calibri",

color: "black",

fontSize: 12,

},

predefinedPlacesDescription: {

color: "black",

},

listView: {

position: "absolute",

marginTop: 44,

backgroundColor:"white",

borderBottomEndRadius: 15,

elevation:2,},}}

nearbyPlacesAPI="GooglePlacesSearch"

GooglePlacesSearchQuery={{

rankby: "distance",

types: "building",}}

filterReverseGeocodingByTypes={[

"locality","administrative_area_level_3",]}

debounce={200}/> </View> </View> <View style={styles.markerFixed}>

<Image

style={styles.marker}

source={require("../../assets/pinmarker.png")}/>

</View> <KeyboardAvoidingView style={styles.footer}>

<View style={{ flexDirection: "row", margin: 10 }}>

<Icon name="ios-home"

size={24}

color="#DC2B6B"

type="ionicon"

style={{

padding: 10,

}}

/>

<Text style={styles.addressText}>Address</Text>

</View>

<TextInput

multiline={true}

clearButtonMode="while-editing"

style={{

marginBottom: 5,

width: "90%",

minHeight: 70,

alignSelf: "center",

borderColor: "lightgrey",

borderWidth: 1.5,

fontSize: 12,

borderRadius: 5,

flex: 0.5,

alignContent: "flex-start",

textAlignVertical: "top",

fontFamily: "Calibri",

}}

onChangeText={(text) =>this.setState({ address: text })}

value={this.state.address}

/>

<TouchableOpacity

onPress={() => {}}

style={{

width: "30%",

alignSelf: "center",

alignItems: "center",

backgroundColor: "lightgreen",

borderRadius: 16.5,

shadowColor: "rgba(0,0,0, .4)", // IOS

shadowOffset: { height: 1, width: 1 }, // IOS

shadowOpacity: 1, // IOS

shadowRadius: 1, //IOS

elevation: 2, // Android

}}>

<Text

style={{

color: "white"

fontFamily: "Calibri",

fontSize: 12,

paddingVertical: 4,

}}>

SAVE

</Text>

</TouchableOpacity>

</KeyboardAvoidingView>

</View>

}

} const styles = StyleSheet.create({

map:{

flex:1

},

markerFixed: {

left: "50%",

marginLeft: -24,

marginTop: -48,

position: "absolute",

top: "50%",

},

addressText: {

color: "black",

margin: 3,

fontFamily: "Calibri",

},

footer: {

backgroundColor: "white",

bottom: 0,

position: "absolute",

width: "100%",

height: "30%",

},

panelFill: {

position: "absolute",

top: 0,

alignSelf: "stretch",

right: 0,

left: 0,

},

panel: {

position: "absolute",

top: 0,

alignSelf: "stretch",

right: 0,

left: 0,

flex: 1,

},

panelHeader: {

//add custom header

},

});

Thats It ! We are done !

We are now able to drag our map around and set the address in the text input box, change our address using Google Auto complete search while the map drags to the location selected and enter address using the text input manually.

Let me know if you face any issues while implementing it and feedbacks are welcome as this is my first attempt.

Happy Coding ! Hakuna Matata !