Security News
The Unpaid Backbone of Open Source: Solo Maintainers Face Increasing Security Demands
Solo open source maintainers face burnout and security challenges, with 60% unpaid and 60% considering quitting.
use-places-autocomplete
Advanced tools
The use-places-autocomplete npm package is a React hook for integrating Google Places Autocomplete functionality into your React applications. It simplifies the process of adding location-based search and suggestions to your app.
Basic Autocomplete
This feature allows you to implement a basic autocomplete input field that provides location suggestions as the user types. It also includes functionality to handle the selection of a suggestion and retrieve its geocode and coordinates.
import React from 'react';
import usePlacesAutocomplete, { getGeocode, getLatLng } from 'use-places-autocomplete';
const PlacesAutocomplete = () => {
const {
ready,
value,
suggestions: { status, data },
setValue,
clearSuggestions
} = usePlacesAutocomplete();
const handleSelect = async (address) => {
setValue(address, false);
clearSuggestions();
try {
const results = await getGeocode({ address });
const { lat, lng } = await getLatLng(results[0]);
console.log("Coordinates: ", { lat, lng });
} catch (error) {
console.log("Error: ", error);
}
};
return (
<div>
<input
value={value}
onChange={(e) => setValue(e.target.value)}
disabled={!ready}
placeholder="Type an address"
/>
{status === 'OK' && (
<ul>
{data.map(({ place_id, description }) => (
<li key={place_id} onClick={() => handleSelect(description)}>
{description}
</li>
))}
</ul>
)}
</div>
);
};
export default PlacesAutocomplete;
Debounced Input
This feature demonstrates how to implement a debounced input field to reduce the number of API calls made as the user types. It uses lodash's debounce function to delay the input handling.
import React from 'react';
import usePlacesAutocomplete, { getGeocode, getLatLng } from 'use-places-autocomplete';
import { debounce } from 'lodash';
const PlacesAutocomplete = () => {
const {
ready,
value,
suggestions: { status, data },
setValue,
clearSuggestions
} = usePlacesAutocomplete();
const handleInput = debounce((e) => {
setValue(e.target.value);
}, 300);
const handleSelect = async (address) => {
setValue(address, false);
clearSuggestions();
try {
const results = await getGeocode({ address });
const { lat, lng } = await getLatLng(results[0]);
console.log("Coordinates: ", { lat, lng });
} catch (error) {
console.log("Error: ", error);
}
};
return (
<div>
<input
onChange={handleInput}
disabled={!ready}
placeholder="Type an address"
/>
{status === 'OK' && (
<ul>
{data.map(({ place_id, description }) => (
<li key={place_id} onClick={() => handleSelect(description)}>
{description}
</li>
))}
</ul>
)}
</div>
);
};
export default PlacesAutocomplete;
react-places-autocomplete is another popular package for integrating Google Places Autocomplete into React applications. It provides a higher-level component-based API compared to use-places-autocomplete, which is a hook-based solution. This package is suitable for developers who prefer working with components rather than hooks.
react-google-autocomplete is a lightweight package that provides a simple component for Google Places Autocomplete. It is less feature-rich compared to use-places-autocomplete but is easier to set up and use for basic autocomplete functionality.
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/googlemaps as a devDependencies
.
$ yarn add --dev @types/googlemaps
# or
$ npm install --save-dev @types/googlemaps
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.
To use this hook, there're two things we need to do:
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
to 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 was loaded.
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 ref = 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 to "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 {
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 the usePlacesAutocomplete
β¨. I just show you how does it work via the minimal example. However you can build an UX rich autocomplete component, like WAI-ARIA compliant and keyword interaction as my demo by checking the code or integrate 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();
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 ready before using this hook. However, you can lazily initialize the hook by the following ways depends on your case.
Option 1, manually initializing the hook:
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>;
};
Option 2, wrap the hook into the conditional component:
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 saving the cost of Google Maps Places API and optimize the search performance as well.
const methods = usePlacesAutocomplete({
// Provide the cache time in seconds, 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
cacheKey: "region-restricted",
});
Note that usePlacesAutocomplete will prefix this with
upa-
, so the above would becomeupa-region-restricted
in sessionStorage.
const returnObj = usePlacesAutocomplete(parameterObj);
When use usePlacesAutocomplete
you can configure the following options via the parameter.
Key | Type | 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 the google.maps to it. |
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. |
cache | number | false | 86400 (24 hours) | Number of seconds to cache the response data of Google Maps Places API. |
cacheKey | string | Optional cache key so one can use multiple caches if needed. | |
defaultValue | string | "" | Default value for the input element. |
initOnMount | boolean | true | Initialize the hook with Google Maps Places API when the component mounts. |
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. | |
clearCache | function | Clears the cached data. | |
init | function | Useful when lazily initializing the hook. |
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.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.place_id}
onClick={handleSelect(suggestion)}
>
{/* Render suggestion text */}
</li>
)
});
return (
<div>
<input value={value} onChange={handleInput} />
{status === 'OK' && <ul>{renderSuggestions()}</ul>}
</div>
);
};
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 ref = 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.place_id}
onClick={handleSelect(suggestion)}
>
{/* Render suggestion text */}
</li>
)
});
return (
<div ref={ref}>
<input value={value} onChange={handleInput} />
{/* After calling the clearSuggestions(), the "status" is reset so the dropdown is hidden */}
{status === 'OK' && <ul>{renderSuggestions()}</ul>}
</div>
);
};
We provide getGeocode, getLatLng, getZipCode and getDetails utils for you to do geocoding and get geographic coordinates when needed.
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) or restrict the results to a specific area by Google Maps Geocoding API.
In case you want to restrict the results to a specific area you will have to pass the address
and the componentRestrictions
matching the GeocoderComponentRestrictions interface.
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 of address
or location
or placeId
and optionally bounds
, componentRestrictions
, region
. 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").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 });
})
.catch((error) => {
console.log("Error: ", error);
});
getLatLng
is an asynchronous function with the following API:
parameter: object
- the result object of getGeocode
.latLng: object
- contains the latitude and longitude properties.error: any
- an exception.It helps you get the postal_code
from the result object of getGeocode
.
import { getGeocode, getZipCode } from "use-places-autocomplete";
const parameter = {
address: "Section 5, Xinyi Road, Xinyi District, Taipei City, Taiwan",
};
getGeocode(parameter)
// By default we use the "long_name" value from API response, you can tell the utility to use "short_name"
// by setting the second parameter to "true"
.then((results) => getZipCode(results[0], false))
.then((zipCode) => {
console.log("ZIP Code: ", zipCode);
})
.catch((error) => {
console.log("Error: ", error);
});
getZipCode
is an asynchronous function with the following API:
parameters
- there're two parameters:
1st: object
- the result object of getGeocode
.2nd: boolean
- should use the short_name
or not from API response, default is false
.zipCode: string | null
- the zip code. If the address doesn't have zip code it will be null
.error: any
- an exception.Retrieves a great deal of information about a particular place ID (suggestion
).
import usePlacesAutocomplete, { getDetails } from "use-places-autocomplete";
const PlacesAutocomplete = () => {
const { suggestions, value, setValue } = usePlacesAutocomplete();
const handleInput = (e) => {
// Place a "string" to update the value of the input element
setValue(e.target.value);
};
const submit = () => {
const parameter = {
// Use the "place_id" of suggestion from the dropdown (object), here just taking first suggestion for brevity
placeId: suggestions[0].place_id,
// Specify the return data that you want (optional)
fields: ["name", "rating"],
};
getDetails(parameter)
.then((details) => {
console.log("Details: ", details);
})
.catch((error) => {
console.log("Error: ", error);
});
};
return (
<div>
<input value={value} onChange={handleInput} />
{/* Render dropdown */}
<button onClick={submit}>Submit Suggestion</button>
</div>
);
};
getDetails
is an asynchronous function with the following API:
parameter: object
- the request of the PlacesService's getDetails()
method. You must supply the placeId
that you would like details about. If you do not specify any fields or omit the fields parameter you will get every field available.placeResult: object | null
- the details about the specific place your queried.error: any
- an exception.β οΈ warning, you are billed based on how much information you retrieve, So it is advised that you retrieve just what you.
π‘ If you have written any blog post or article about
use-places-autocomplete
, please open a PR to add it here.
Thanks goes to these wonderful people (emoji key):
Welly π» π π§ | Kyle π | Lazar KariΔ π» π | Raif Harik π» π π€ | Xerxes Jarquin π | Lucas O'Connell π | Keven Jesus π |
Vinicius Uehara π | Damon π» |
This project follows the all-contributors specification. Contributions of any kind welcome!
FAQs
React hook for Google Maps Places Autocomplete.
The npm package use-places-autocomplete receives a total of 117,940 weekly downloads. As such, use-places-autocomplete popularity was classified as popular.
We found that use-places-autocomplete demonstrated a not healthy version release cadence and project activity because the last version was released a year ago.Β It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Solo open source maintainers face burnout and security challenges, with 60% unpaid and 60% considering quitting.
Security News
License exceptions modify the terms of open source licenses, impacting how software can be used, modified, and distributed. Developers should be aware of the legal implications of these exceptions.
Security News
A developer is accusing Tencent of violating the GPL by modifying a Python utility and changing its license to BSD, highlighting the importance of copyleft compliance.