Loading repository dataβ¦
Loading repository dataβ¦
wellyshen / repository
π π React hook for Google Maps Places Autocomplete.
π We're actively seeking dedicated maintainers for the repo β if you're interested, please contact me directly.
This is a React hook for Google Maps Places Autocomplete, which helps you build a UI component with the feature of place autocomplete easily! By leveraging 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.
β€οΈ it? βοΈ it on GitHub or Tweet about it.

β‘οΈ Try yourself: https://use-places-autocomplete.netlify.app
react.To use use-places-autocomplete, you must use react@16.8.0 or greater which includes hooks.
This package is distributed via npm.
$ yarn add use-places-autocomplete
# or
$ npm install --save use-places-autocomplete
When working with TypeScript you need to install the @types/google.maps as a devDependencies.
$ yarn add --dev @types/google.maps
# or
$ npm install --save-dev @types/google.maps
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 review them before we start.
To use this hook, there're two things we need to do:
Use the script tag to load the library in your project and pass the value of the callback parameter to the callbackName option.
<script
defer
src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places&callback=YOUR_CALLBACK_NAME"
></script>
β οΈ If you got a global function not found error. Make sure
usePlaceAutocompleteis declared before the script was loaded. You can use the async or defer attribute of the<script>element to achieve that.
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({
callbackName: "YOUR_CALLBACK_NAME",
requestOptions: {
/* Define search scope here */
},
debounce: 300,
});
const ref = useOnclickOutside(() => {
// When the 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 the user selects a place, we can replace the keyword without request data from API
// by setting the second parameter to "false"
setValue(description, false);
clearSuggestions();
// Get latitude and longitude via utility functions
getGeocode({ address: description }).then((results) => {
const { lat, lng } = getLatLng(results[0]);
console.log("π Coordinates: ", { lat, lng });
});
};
const renderSuggestions = () =>
data.map((suggestion) => {
const {
place_id,
structured_formatting: { main_text, secondary_text },
} = suggestion;
return (
<li key={place_id} onClick={handleSelect(suggestion)}>
<strong>{main_text}</strong> <small>{secondary_text}</small>
</li>
);
});
return (
<div ref={ref}>
<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>
);
};
π‘ react-cool-onclickoutside is my other hook library, which can help you handle the interaction of user clicks outside of the component(s).
Easy right? This is the magic of usePlacesAutocomplete β¨. I just showed you how it works via a minimal example. However, you can build a UX rich autocomplete component, like WAI-ARIA compliant and keyword interaction like my demo, by checking the code or integrating this hook with the combobox of Reach UI to achieve that.
import usePlacesAutocomplete from "use-places-autocomplete";
import {
Combobox,
ComboboxInput,
ComboboxPopover,
ComboboxList,
ComboboxOption,
} from "@reach/combobox";
import "@reach/combobox/styles.css";
const PlacesAutocomplete = () => {
const {
ready,
value,
suggestions: { status, data },
setValue,
} = usePlacesAutocomplete({ callbackName: "YOUR_CALLBACK_NAME" });
const handleInput = (e) => {
setValue(e.target.value);
};
const handleSelect = (val) => {
setValue(val, false);
};
return (
<Combobox onSelect={handleSelect} aria-labelledby="demo">
<ComboboxInput value={value} onChange={handleInput} disabled={!ready} />
<ComboboxPopover>
<ComboboxList>
{status === "OK" &&
data.map(({ place_id, description }) => (
<ComboboxOption key={place_id} value={description} />
))}
</ComboboxList>
</ComboboxPopover>
</Combobox>
);
};
When loading the Google Maps Places API via a 3rd-party library, you may need to wait for the script to be ready before using this hook. However, you can lazily initialize the hook in the following ways, depending on your use case.
import usePlacesAutocomplete from "use-places-autocomplete";
const App = () => {
const { init } = usePlacesAutocomplete({
initOnMount: false, // Disable initializing when the component mounts, default is true
});
const [loading] = useGoogleMapsApi({
library: "places",
onLoad: () => init(), // Lazily initializing the hook when the script is ready
});
return <div>{/* Some components... */}</div>;
};
import usePlacesAutocomplete from "use-places-autocomplete";
const PlacesAutocomplete = () => {
const { ready, value, suggestions, setValue } = usePlacesAutocomplete();
return <div>{/* Some components... */}</div>;
};
const App = () => {
const [loading] = useGoogleMapsApi({ library: "places" });
return (
<div>
{!loading ? <PlacesAutocomplete /> : null}
{/* Other components... */}
</div>
);
};
By default, this library caches the response data to help you save the cost of Google Maps Places API and optimize search performance.
const methods = usePlacesAutocomplete({
// Provide the cache time in seconds, the default is 24 hours
cache: 24 * 60 * 60,
});
By the way, the cached data is stored via the Window.sessionStorage API.
You may need to have multiple caches. For example, if you use different place type restrictions for different pickers in your app.
const methods = usePlacesAutocomplete({
// Provide a custom cache key