wellyshen / use-places-autocomplete Goto Github PK
View Code? Open in Web Editor NEW๐ ๐ React hook for Google Maps Places Autocomplete.
Home Page: https://use-places-autocomplete.netlify.app
License: MIT License
๐ ๐ React hook for Google Maps Places Autocomplete.
Home Page: https://use-places-autocomplete.netlify.app
License: MIT License
Due to expected high volume of request goign to Places API i was wondering what kind of SKU do you use under the hood to make request some are free and some are whoping $17 per 1k requests.
See more : Basic SKU
Overall its such a nice component good job.
I have integrated google-map-react with use-places-autocomplete hook.
From what i understand, on component mount this hook is not able to find the google.maps object
Error can be reproduced on searching with any key on input, in code-sandbox here: Code Sandbox example ->
What is the way around to fix this?
Suppose we have a component where a user can select a country then the autocomplete only shows addresses from that country:
const [country, setCountry] = useState('GB');
const { suggestions, setValue } = usePlacesAutocomplete({
requestOptions: {
componentRestrictions: { country },
},
});
When we search for 123
, it returns some British addresses - so far so good. Now if we setCountry('US')
and type 123
again it returns the cached British addresses instead of doing a new search for US addresses.
Several releases under 1.*.*
include breaking changes, but have not bumped the major version of the package.
https://github.com/wellyshen/use-places-autocomplete/releases
Semver dictates that once you release >=1.0.0 version, then all breaking changes necessitate major version increment.
Please increment the major version of the package the next time you are releasing breaking changes.
Whoops, I was wrong about this, sorry.
Hey, the demo code doesn't have the Google logo and attributions and it violates the API use policy
If this is out of the demo scope, we must at least add some text to make this clear.
Add screenshots to help explain your problem.
https://developers.google.com/maps/documentation/javascript/places-autocomplete#policies
When the getDetails function is called on a place id, it returns all the fields which you are charged for on each API call. Google Maps API autocomplete documentation has the following value to limit the data returned:
autocomplete.setFields(["address_components", "geometry", "icon", "name"]);
https://developers.google.com/maps/documentation/javascript/examples/places-autocomplete
Are these options able to be passed into the getDetails function?
Can you suggest how can we use useplacesautocomplete hook multiple time on same page. Like say for from address and to address
I think "getZipCode" utility function would be very helpful for me and everyone else. For example, I use your hook on my address field and I try to auto-populate zip code on another field.
Currently, I get results from "getGeocode" and iterate through them and manually take out "postal_code" from "address_components" array.
I hope you understand :)
A small link anchoring bug within README.md (only in npmjs.com though)
If you wish I can make a PR to fix this issue.
Hi everyone,
I got a issue and can not using autocomplete place, I have try to fix it but still not resolve it
In env local, I load script google map not get any issue, but env production I got the following error.
Refused to load the script 'https://maps.googleapis.com/maps/api/js?v=weekly&key=xxxxxyyyyyyddฤd&libraries=places&language=vi' because it violates the following Content Security Policy directive: "script-src 'self' 'unsafe-inline' 'unsafe-eval' www.googletagmanager.com connect.facebook.net www.googleadservices.com www.google-analytics.com googleads.g.doubleclick.net onesignal.com tpc.googlesyndication.com". Note that 'script-src-elem' was not explicitly set, so 'script-src' is used as a fallback.
This is how I try, but still can not fix it:
<meta httpEquiv="Content-Security-Policy" content="script-src 'self' 'unsafe-eval' 'unsafe-inline' developers.google.com maps.googleapis.com https://www.googletagmanager.com https://connect.facebook.net https://www.googleadservices.com https://www.google-analytics.com https://googleads.g.doubleclick.net https://onesignal.com https://tpc.googlesyndication.com;" />
And don't know where the other sources are called from, because I don't use it like: www.googletagmanager.com, connect.facebook.net, www.googleadservices.com, www.google-analytics.com, googleads.g.doubleclick .net,...
Looking forward to all the helpers. Thanks all.
Source:
Hello!
first of all, thanks for your work, I'm based mine of it :)
I'm concerned about the getGeocode
utility and the fact that it doesn't use PlacesService.getDetails. I think it is important to be able to build a user session and reduce API usage costs by specifying a AutoCompleteSessionToken, which is currently supported by the usePlacesAutocomplete
hook (in requestOptions
) but not the getGeocode
function.
Am I correct?
I'm trying to async load script only in one component. I get not errors but ready
is always false. My code:
const PlaceAutocomplete =( ) => {
const {
ready,
value,
suggestions: { status, data },
setValue,
clearSuggestions
} = usePlacesAutocomplete({
callbackName: 'initMap',
debounce: 300
});
useEffect(()=> {
const createScriptLoadMap = () => {
if (!window.initMap) {
var index = window.document.getElementsByTagName("script")[0];
var script = window.document.createElement("script");
script.src =
"https://maps.googleapis.com/maps/api/js?key=******&libraries=places&callback=initMap"; //
script.async = true;
script.defer = true;
index.parentNode.insertBefore(script, index);
window.initMap = true;
}
};
createScriptLoadMap();
},[])
// rest of code
First of all, thanks for this library.
I'm trying to use this hook to initialize the Google api, however I have one question.
Where does useGoogleMapsApi() imported from?
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>;
};
Hello,
Could you export the types defined by the library? I'd appreciate having access to AutocompletePrediction, to add it to argument of handleSelect function.
Or there is another way to do it with typescript?
Thank you ๐
Hello,
I'm trying to use yours basic example to be able to understand how to use your module in my system but seems nothing to work. I don't have any console errors and have no idea what wrong actually. I hope you can help me to understand what I'm missing.
Thank you and the code
import { useLoadScript } from '@react-google-maps/api';
import useOnclickOutside from 'react-cool-onclickoutside';
import usePlacesAutocomplete, {
getGeocode,
getLatLng,
} from 'use-places-autocomplete';
const libraries = ['places'];
export default function AutoCompletePlaces() {
console.log('IS IT RUNNING ????');
const API_KEY = process.env.GOOGLE_PLACES_API_KEY;
const { isLoaded, loadError } = useLoadScript({
googleMapsApiKey: API_KEY,
libraries,
});
console.log('LOADED ????', isLoaded, loadError);
const {
ready,
value,
suggestions: { status, data },
setValue,
clearSuggestions,
} = usePlacesAutocomplete({
// requestOptions: {
// /* Define search scope here */
// },
debounce: 300,
});
console.log(status, data);
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 }) => () => {
console.log(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 loadError || !isLoaded ? (
<div>FAIL</div>
) : (
<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>
);
Hello,
According to Google's documentation, the geocoder API allows doing that with location (LatLng) option. It would be nice to have it supported by GetGeocode too.
My use case is: I only have a LatLnt param and need to get the point's metadata.
I want to expand the GetGeocode's interface to have that option and add additional parameters validation.
I'm asking about before doing any contribution, according to the project's recommendations.
Thank you.
To reduce costs, Google requires autocomplete requests include a session token: https://developers.google.com/places/web-service/usage-and-billing
Passing in a simple string (for example, generated by uui()) passes typecheck, but then fails when making the request with the error: "in property sessionToken: not an instance of AutocompleteSessionToken", name: "InvalidValueError""
The top-level export file does not include the necessary class to create an AutocompleteSessionToken, meaning it is impossible to include a sessionToken in the request (without modifying this library)
passing the requestOptions doesn't seem to work. Looking at the google doc https://developers.google.com/maps/documentation/javascript/reference/places-autocomplete-service#AutocompletionRequest it should be possible to restrict results from an specific country by passing the property componentRestrictions.country with the country code. found here https://developers.google.com/maps/documentation/javascript/reference/places-autocomplete-service#ComponentRestrictions
I'm pretty new with react so maybe this isn't bug but maybe I have done something wrong in my code.
inside requestOptions, simply put
componentRestrictions: {
country: 'sv'
}
https://codesandbox.io/s/useplacesautocomplete-x-reach-ui-forked-qo84h
in the same demo as you already have. Look at line 25 in this forked sandbox
I expect this code to only show results from the country SV (sweden)
componentRestrictions: {
country: 'sv'
}
I really like this! Except from this it works grate in my app!
If this is not a bug, I would really appreciate help to get it to work !
This is not a bug, this just a thank you guys, this was very helpfull
It's already great that you implemented debouncing to reduce API calls, but Google will nevertheless charge per each of these request. However, there's a parameter called sessionToken that can be sent to group one autocompletion and be charged only once.
These are some links about this feature:
Places API documentation
https://developers.google.com/maps/documentation/javascript/reference/places-autocomplete-service#AutocompleteSessionToken
They mentioned it when they introduced the pricing changes
https://cloud.google.com/maps-platform/user-guide/pricing-changes/
In the example for the query here it's all lowercased (so sessiontoken instead of sessionToken)
https://developers.google.com/places/web-service/usage-and-billing#ac-with-details-session
Thank you for making this React hook, by the way!
It would be great that this library offers out of the box caching of the results so we don't request new queries for the same inputed search criteria within the same user session. This could potentially help saving costs.
GLatLng not exported.
Trying to use
usePlacesAutocomplete({
debounce: 300,
requestOptions: {
location: new GLatLng(19.419224, -99.171446),
},
})
But can't access GLatLng class since it's not exported.
Run this code:
`import usePlacesAutocomplete, GLatLng, from "use-places-autocomplete"
usePlacesAutocomplete({
debounce: 300,
requestOptions: {
location: new GLatLng(19.419224, -99.171446),
},
})`
GLatLng is expected but not exported in the module :(
GLatLng should be expected
Thanks for the awesome work.
We are using load-google-maps-api
to load google maps api with useEffect when the component loads. Because there is no script that we can set callback
name and useEffect
runs after component loads, the ready
state returned by usePlacesAutocomplete
is always false and it stays that way until the component is "remounted" (e.g navigate away and back). The workaround we found is setting a fake callback name as a state and pass it to usePlacesAutocomplete
, once the load google maps promise resolves we set the callback name to undefined
, which triggers the effect calling init
function in use-places-autocomplete
(because callbackName
is one of the dependencies of that effect). This works fine but it's coupled to the library's internal implementation. Is there a better way to solve this or could you add support for loading google maps api via third party library?
I think if the usePlacesAutocomplete
hook could expose the init
function for users to call it whenever the google maps api is loaded, the above issue would be solved.
Hello. I have an "Invalid hook call" and "Cors origin" problem with this library. How do you think, how can I fix it?
Failed to read the 'sessionStorage' property from 'Window': Access is denied for this document.
Sometimes the suggestions are not showing and console logs this error. Failed to read the 'sessionStorage' property from 'Window': Access is denied for this document.
No clear steps to reproduce.
It should work even session storage throws an error
how to use it for multiple inputs, i would need 3?
Debounce not working when using requestOptions
requestOptions
in the hook:usePlacesAutocomplete({
requestOptions: {},
debounce: 300
});
But it works when there's no requestOptions
:
usePlacesAutocomplete({
debounce: 300
});
I'm trying to get only countrynames from Places API using types in requestOptions.
Accordingly to this documentation it should be possible
Google's RequestOptions Doc: https://developers.google.com/maps/documentation/places/web-service/supported_types#table3
However when I execute this code here:
Expectate behaviour:
I expect it to show me only countrynames on proper input and nothing on bad input (when country does not start with searchstring it wont show anything.
Am I using it in a wrong way or is it really a bug?
A default location shown on the autocomplete input as soon as ui rendered.
If user's location is shared via browser geolocation api use that lat lang to display default location, user can change that obviously if needed.
It should enabled via a config variable.
e.g
showCurrentLocationOnLoad: true | false
Hi Welly!
I'm making a web app where I'd like to pass the {lat, lng}
object from the getGeocode Custom Hook to another component as a props. That component will these use each coordinate as a parameter to a Rest API request.
getGeocode({ address: description })
.then((results) => getLatLng(results[0]))
.then(({ lat, lng }) => {
console.log('๐ Coordinates: ', { lat, lng })
})
.catch((error) => {
console.log('๐ฑ Error: ', error)
})
I think the part where I am getting hung up is the React's unidirectional data flow. I am having trouble getting the {lat, lng}
object "back up" out of my AddressInput.js component and into my "root" component App.js, where I then want to pass {lat, lng}
into another component as props.
I realize that I am probably thinking about the app's structure the wrong way. Should I instead be calling the API in a useEffect
Hook? Thanks in advance for any advice you may be able to provide!
Right now the getGeocode method only accepts an address or a place id.
The Google Geocoding service can accept a component restrictions parameter to restricted results to a specific area.
Update the getGeocode method to accept component restrictions as PlaceAutocomplete.
If you have no time to do it, I can try to find some time to create a pull request this week.
When using the autocomplete in TypeScript, suggestions.data
is an array of type any
. I believe this to be because AutocompletePrediction
is any
since it doesn't exist in the index.d.ts
file.
import usePlacesAutocomplete from 'use-places-autocomplete';
export const AutocompleteLocation = (): JSX.Element => {
const {
suggestions: {
data,
},
setValue,
} = usePlacesAutocomplete({
requestOptions: {
componentRestrictions: { country: 'us' },
},
callbackName: 'loadPlaceAutocomplete',
debounce: 300,
});
/**
* The below will result in "Unsafe member access .description on an any value." since `data` is an array of `any`.
* Note that I am seeing this when using typescript-eslint.
*/
data.map((suggestion) => suggestion.description);
};
That suggestions.data
is properly typed instead of any
Any other information about the problem here.
GitHub Issues are reserved for Bug reports and Feature requests. Support requests that are created as issues are likely to be closed. We want to make sure you are able to find the help you seek. Please take a look at the following resources.
If you have a coding question related to React, it might be better suited for Stack Overflow. It's a great place to browse through frequent questions about using React, as well as ask for help with specific questions.
https://stackoverflow.com/questions/tagged/react
There are many online forums which are a great place for discussion about best practices and application architecture.
https://reactjs.org/community/support.html#popular-discussion-forums
Great library! Will you support react native in the future?
The API specification lists a language
parameter, but this library isn't including it as a valid option (not sure if it was an omission or if this parameter was recently added).
https://developers.google.com/places/web-service/autocomplete
Try to add the language
parameter to requestOptions
on a TS project, it will complain.
language
parameter should be accepted in requestOptions
and it should be send to Google Autocomplete services
I tried to load the google api script in the component using useEffect
useEffect(() => {
loadGoogleMaps();
}, []);
const loadGoogleMaps = async () => {
const google = await loadScript(
'https://maps.googleapis.com.......',
'google'
);
};
The script loads just after or at the same time as my component, and suddenly the 1st time the autocomplete does not work.
I can put the load script in index.tsx
or app.tsx
, but I prefer to keep it in the same component as autocomplete !
Thanks !
I started implementing your library which is really well done by the way but I've noticed that "requestOptions" parameter has the wrong type which forbids me to set "requestOptions.strictBounds = true". Changing type should allow me to fix my issue which is a very import feature to us (see https://developers.google.com/maps/documentation/javascript/reference/places-widget?hl=en#AutocompleteOptions).
Thank you in advance!
I want load google map asyncly with useScript hook, https://usehooks.com/useScript/
but get error such below
'> ๐กuse-places-autocomplete: Google Maps Places API library must be loaded. See: https://github.com/wellyshen/use-places-autocomplete#load-the-library';
Hi. Thank you for this library. It appears that the Google Maps Javascript API might be outdated, see error message:
Google Maps JavaScript API warning: RetiredVersion https://developers.google.com/maps/documentation/javascript/error-messages#retired-version
Simply use the hook in normal form operation.
Would be great if the warning was removed.
Thanks.
Hello,
I have a query about the loading status in suggestions
const {
ready,
value: autocompleteValue,
suggestions: { data, status, loading },
clearSuggestions,
setValue,
} = usePlacesAutocomplete({
debounce: 3000,
});
This loading is very fast and the spinner I attached to show on loading appears for a millisecond and I would like to understand how to delay this or if there is a better way of doing it?
I want to show up my loader spinner
const isLoading = () => {
return loading ? <CircularProgress color="inherit" size={20} /> : null;
};
Thank you :)
The documentation refers to a demo/code which is more UX rich including "a keyword clear button, search history"
Having implemented the code example I don't see these two features, so I'm wondering if I'm missing something here? Are there any code examples available for these two features?
Thanks
It might be useful to create an alternative demo using https://reacttraining.com/reach-ui/combobox as it accomplices the same thing as what you're doing with the current demo with a proven solution as well.
https://reacttraining.com/reach-ui/combobox
Might be worth looking into!
Hi, here
a43e1b1#diff-39b2554fd18da165b59a6351b1aafff3714e2a80c1435f2de9706355b4d32351L70
there is a change. It used to be the case that if you passed in just the place_id it would work or if you passed in the "suggestion" it would pull the place_id out of it and it would work.
Now neither of those work you have pass in an object with a camelcased placeId on it. This is not good. It is a breaking change for no advantage that I can tell. I you want the sig to take string | {place_id: string} | {placeId: string}
then that's find but why break it for those using it the old way?
Hi Everyone
is there way to access native api and use func setComponentRestrictions
Best regards,
Toan
I've checked the documentation but I can't find how to display the attribution. Is there any way to turn this on?
Google docs says it's just an image. So, should I grab the attribution image from the docs and serve it from my server or is there anyway to turn this on?
Demo app doesn't work https://use-places-autocomplete.netlify.app/
Try to search on demo website
Error in console about API key not loading
Thank you for the awesome package!
I skimmed through the docs [1, 2, and 3] I'm still a bit confused as per how to request the types in order to retrieve the country, city etc in the returned suggestions.
It would be very helpful if the docs would include at least one basic example of how to use requestOptions
instead of just having a placeholder /* Define search scope here */
PS.
And in case my gut feels is right and the requestOptions
are not at all meant to alter the response for the formatting, then perhaps any pointers on how one could go about this? But would still be nice to have an example that explains the purpose of requestOptions
in more detail. :)
Thanks again for this package! ๐๐ผ
Sources:
https://developers.google.com/maps/documentation/javascript/reference/places-autocomplete-service#AutocompletionRequest
https://developers.google.com/places/supported_types#table3
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.