React hook for Google Maps Places Autocomplete
usePlacesAutocomplete
This is a React hook of Google Maps Places Autocomplete, which helps you build an UI component with the feature of place autocomplete easily! By leverage the power of Google Maps Places API, you can provide a great UX (user experience) for user interacts with your search bar or form etc. Hope you guys it.
Features
- ? Provide intelligent places suggestions powered by Google Maps Places API.
- ? Build your own customized autocomplete UI by React hook.
- ? Utility functions to do geocoding and get geographic coordinates using Google Maps Geocoding API.
- ?️ Support asynchronous Google script loading.
- ? Support TypeScript type definition.
- ⌨️ Build an UX rich component (e.g. WAI-ARIA compliant and keyword support) via comprehensive demo code.
Requirement
To use use-places-autocomplete
, you must use react@16.8.0
or greater which includes hooks.
Installation
This package is distributed via npm.
$ yarn add use-places-autocomplete
# or
$ npm install --save use-places-autocomplete
Getting Started
usePlacesAutocomplete
is based on the Places Autocomplete (or more specific docs) of Google Maps Place API. If you are unfamiliar with these APIs, we recommend you reviewing them before we start.
Setup APIs
To use this hook, there're two things we need to do:
Load the library
Use the script
tag to load the library in your project.
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places"></script>
We also support asynchronous script loading. By doing so you need to pass the initMap
as the callbackName option.
<script async defer
src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places&callback=initMap"
></script>
⚠️ If you got a global function not found error. Make sure
usePlaceAutocomplete
is declared before the script is loaded.
Create the component
Now we can start to build our component. Check the API out to learn more.
import usePlacesAutocomplete, { getGeocode, getLatLng } from 'use-places-autocomplete';
import useOnclickOutside from 'react-cool-onclickoutside';
const PlacesAutocomplete = () => {
const {
ready,
value,
suggestions: { status, data },
setValue,
clearSuggestions
} = usePlacesAutocomplete({
requestOptions: { /* Define search scope here */ }
debounce: 300
});
const registerRef = useOnclickOutside(() => {
// When user clicks outside of the component, we can dismiss
// the searched suggestions by calling this method
clearSuggestions();
});
const handleInput = e => {
// Update the keyword of the input element
setValue(e.target.value);
};
const handleSelect = ({ description }) => () => {
// When user selects a place, we can replace the keyword without request data from API
// by setting the second parameter as "false"
setValue(description, false);
clearSuggestions();
// Get latitude and longitude via utility functions
getGeocode({ address: description })
.then(results => getLatLng(results[0]))
.then(({ lat, lng }) => {
console.log('? Coordinates: ', { lat, lng });
}).catch(error => {
console.log('? Error: ', error)
});
};
const renderSuggestions = () =>
data.map(suggestion => {
const {
id,
structured_formatting: { main_text, secondary_text }
} = suggestion;
return (
<li
key={id}
onClick={handleSelect(suggestion)}
>
<strong>{main_text}</strong> <small>{secondary_text}</small>
</li>
);
});
return (
<div ref={registerRef}>
<input
value={value}
onChange={handleInput}
disabled={!ready}
placeholder="Where are you going?"
/>
{/* We can use the "status" to decide whether we should display the dropdown or not */}
{status === 'OK' && <ul>{renderSuggestions()}</ul>}
</div>
);
};
Easy right? This is the magic of the usePlacesAutocomplete
✨. I just show you how does it work via the minimal example. However there're more things you can do for an UX rich autocomplete component, like WAI-ARIA compliant and keyword support as my demo (check the code), a keyword clear button, search history etc.
? react-cool-onclickoutside is my other hook library, which can help you handle the interaction of user clicks outside of the component(s).
API
const return = usePlacesAutocomplete(parameter);
Parameter object (optional)
When use usePlacesAutocomplete
you can configure the following options via the parameter.
Key | Type (all optional) | Default | Description |
---|---|---|---|
requestOptions |
object | The request options of Google Maps Places API except for input (e.g. bounds, radius etc.). |
|
googleMaps |
object | window.google.maps |
In case you want to provide your own Google Maps object, pass it in as google.maps . |
callbackName |
string | You can provide a callback name to initialize usePlacesAutocomplete after Google script is loaded. It's useful when you load the script asynchronously. |
|
debounce |
number | 200 |
Number of milliseconds to delay before making a request to Google Maps Places API. |
Return object
It's returned with the following properties.
Key | Type | Default | Description |
---|---|---|---|
ready |
boolean | false |
The ready status of usePlacesAutocomplete . |
value |
string | '' |
value for the input element. |
suggestions |
object | { loading: false, status: '', data: [] } |
See suggestions. |
setValue |
function | (value, shouldFetchData = true) => {} |
See setValue. |
clearSuggestions |
function | See clearSuggestions. |
suggestions
The search result of Google Maps Places API, which contains the following properties:
loading: boolean
- indicates the status of a request is pending or has completed. It's useful for displaying a loading indicator for user.status: string
- indicates the status of API response, which has these values. It's useful to decide whether we should display the dropdown or not.data: array
- an array of suggestion objects each contains all the data.
setValue
Set the value
of the input element. Use case as below.
import usePlacesAutocomplete from 'use-places-autocomplete';
const PlacesAutocomplete = () => {
const { value, setValue } = usePlacesAutocomplete();
const handleInput = e => {
// Place a "string" to update the value of the input element
setValue(e.target.value);
};
return (
<div>
<input value={value} onChange={handleInput} />
{/* Render dropdown */}
</div>
);
};
In addition, the setValue
method has an extra parameter, which can be used to disable hitting Google Maps Places API.
import usePlacesAutocomplete from 'use-places-autocomplete';
const PlacesAutocomplete = () => {
const {
value,
suggestions: { status, data },
setValue
} = usePlacesAutocomplete();
const handleSelect = ({ description }) => () => {
// When user select a place, we can replace the keyword without request data from API
// by setting the second parameter to "false"
setValue(description, false);
};
const renderSuggestions = () =>
data.map(suggestion => (
<li
key={suggestion.id}
onClick={handleSelect(suggestion)}
>
{/* Render suggestion text */}
</li>
)
});
return (
<div>
<input value={value} onChange={handleInput} />
{status === 'OK' && <ul>{renderSuggestions()}</ul>}
</div>
);
};
clearSuggestions
Calling the method will clear and reset all the properties of the suggestions
object to default. It's useful for dismissing the dropdown.
import usePlacesAutocomplete from 'use-places-autocomplete';
import useOnclickOutside from 'react-cool-onclickoutside';
const PlacesAutocomplete = () => {
const {
value,
suggestions: { status, data },
setValue,
clearSuggestions
} = usePlacesAutocomplete();
const registerRef = useOnclickOutside(() => {
// When user clicks outside of the component, call it to clear and reset the suggestions data
clearSuggestions();
});
const renderSuggestions = () =>
data.map(suggestion => (
<li
key={suggestion.id}
onClick={handleSelect(suggestion)}
>
{/* Render suggestion text */}
</li>
)
});
return (
<div ref={registerRef}>
<input value={value} onChange={handleInput} />
{/* After calling the clearSuggestions(), the "status" is reset so the dropdown is hidden */}
{status === 'OK' && <ul>{renderSuggestions()}</ul>}
</div>
);
};
Utility Functions
We provide getGeocode and getLatLng utils for you to do geocoding and get geographic coordinates when needed.
getGeocode
It helps you convert address (e.g. "Section 5, Xinyi Road, Xinyi District, Taipei City, Taiwan") into geographic coordinates (e.g. latitude 25.033976 and longitude 121.5645389) by Google Maps Geocoding API.
import { getGeocode } from 'use-places-autocomplete';
const parameter = {
address: 'Section 5, Xinyi Road, Xinyi District, Taipei City, Taiwan',
// or
placeId: 'ChIJraeA2rarQjQRPBBjyR3RxKw'
};
getGeocode(parameter)
.then(results => {
console.log('Geocoding results: ', results);
})
.catch(error => {
console.log('Error: ', error);
});
getGeocode
is an asynchronous function with the following API:
parameter: object
- you must supply one, only one ofaddress
orplaceId
. It'll be passed as Geocoding Requests.results: array
- an array of objects each contains all the data.error: string
- the error status of API response, which has these values (except for "OK").
getLatLng
It helps you get the lat
and lng
from the result object of getGeocode
.
import { getGeocode, getLatLng } from 'use-places-autocomplete';
const parameter = {
address: 'Section 5, Xinyi Road, Xinyi District, Taipei City, Taiwan'
};
getGeocode(parameter)
.then(results => getLatLng(results[0]))
.then(latLng => {
const { lat, lng } = latLng;
console.log('Coordinates: ', { lat, lng });
});
getLatLng
is an asynchronous function with the following API:
parameter: object
- the result object ofgetGeocode
.latLng: object
- contains the latitude and longitude properties.