wellyshen / use-places-autocomplete

😎 📍 React hook for Google Maps Places Autocomplete.
https://use-places-autocomplete.netlify.app
MIT License
1.25k stars 64 forks source link

Google API now requires callback function parameter #1120

Closed LucasLemanowicz closed 1 year ago

LucasLemanowicz commented 1 year ago

Bug Report

Describe the Bug

Importing the Google API script now requires you to set the callback URL parameter (https://developers.google.com/maps/documentation/javascript/url-params#required_parameters). Not including it now throws a console error on every page load, as seen in the demo of this library when you open the javascript console: https://use-places-autocomplete.netlify.app/

How to Reproduce

Steps to reproduce the behavior, please provide code snippets or a repository:

  1. Import the Google API library without passing in a callback function:
    <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places"></script>
  2. Follow the remaining instructions in the README
  3. Load the page, open console, see error

Expected Behavior

There should be no console error

Screenshots

Screen Shot 2023-01-20 at 10 12 15 AM

Your Environment

wellyshen commented 1 year ago

@LucasLemanowicz Thank you for reporting this issue, I have updated the document. ✌🏻

mech commented 1 year ago

I am puzzle what we should do in the callback function. Maybe provide some example?

If we don't do anything in the callback function, is it we still need to provide an empty no-op function?

wellyshen commented 1 year ago

@mech Just give the value of the callback parameter to the hook, it will do magic for you 😉

LucasLemanowicz commented 1 year ago

@mech if you look at this useEffect hook, callbackName is being used to assign usePlacesAutocomplete's init function to a global window function of that name, which is what the Google Place API will call once it loads: https://github.com/wellyshen/use-places-autocomplete/blob/c67fd9f/src/usePlacesAutocomplete.ts#L171-L175

That init function then initializes usePlacesAutocomplete: https://github.com/wellyshen/use-places-autocomplete/blob/c67fd9f/src/usePlacesAutocomplete.ts#L65-L79

mech commented 1 year ago

Oh now I get it. The function itself has already been implemented and I am just going to give it a "any" string I like but it must be matched with the query string parameter.

Example:

<script
  defer
  src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places&callback=initMap
></script>

I am using the string "initMap", then at the React side:

const x = usePlacesAutocomplete({callbackName: "initMap"})

The fact of the matter is that this "initMap" named function we do not need to implement ourselves.

mech commented 1 year ago

Not sure if I do it wrong, but I got this error:

{message: 'initMap is not a function', stack: 'Error\n    at _.He.captureStackTrace (https://maps.…ly&language=en&region=SG&callback=initMap:222:255', name: 'InvalidValueError'}

With a InvalidValueError error.

I actually try to follow this commit code:

https://github.com/wellyshen/use-places-autocomplete/commit/01eb40beb0794a84a5ab4e27eeea38c57a47e8e3

This error message also appear at: https://use-places-autocomplete.netlify.app/

wellyshen commented 1 year ago

This error message also appear at: https://use-places-autocomplete.netlify.app/

That's because the JavaScript file of React.js isn't loaded after the Google Maps library. Once the loading ordering of the scripts is correct the error should be gone.

l3onwu commented 1 year ago

This error message also appear at: https://use-places-autocomplete.netlify.app/

That's because the JavaScript file of React.js isn't loaded after the Google Maps library. Once the loading ordering of the scripts is correct the error should be gone.

Hey did you ever solve this? Have done the same as above, but getting the same error, even with async and defer keywords for the script tag.

mech commented 1 year ago

Do you have more information on this error again. I am not too sure what is meant by:

That's because the JavaScript file of React.js isn't loaded after the Google Maps library.

I am using Next.js, so I believe the whole of React should be loaded in the first place.

apuntovanini commented 1 year ago

I also face the same issue no matter the async or defer Only way I get rid of the error is setting

<script async defer src="https://maps.googleapis.com/maps/api/js?key=<%= Rails.application.secrets.google[:key] %>&libraries=places&callback=googleMapsCallback"></script>
<script>
window.googleMapsCallback = () => {}
</script>

in <head> tag

Is this ok?

l3onwu commented 1 year ago

I'm using create-react-app and was encountering the issue. Seems to be due to inconsistencies with how react is loaded, as sometimes I encountered the error and sometimes I did not.

What solved it for me was to set initOnMount as 'false', and use another library to load google maps API. I then initalized the use-places-autocomplete as a callback to the library loading. https://www.npmjs.com/package/load-google-maps-api

jasan-s commented 1 year ago

how is this closed? this is still an issue

wellyshen commented 1 year ago

how is this closed? this is still an issue

The problem is not with this library, but with the loading order of the React and Google Maps API scripts. Make sure that the Google Maps API is loaded after the hook, as demonstrated by @l3onwu here.

vileen commented 1 year ago

I also face the same issue no matter the async or defer Only way I get rid of the error is setting

<script async defer src="https://maps.googleapis.com/maps/api/js?key=<%= Rails.application.secrets.google[:key] %>&libraries=places&callback=googleMapsCallback"></script>
<script>
window.googleMapsCallback = () => {}
</script>

in <head> tag

Is this ok?

you can just pass Function.prototype as callback if you don't need it, that way you'll avoid declaring useless function

MiguelNiblock commented 10 months ago

I ended up loading the library during app initialization, using a little 3rd party helper specific for loading the google maps api. https://www.npmjs.com/package/load-google-maps-api

This is equivalent to loading the hook inside a conditional component. But in my app, the more reliable thing was for the entire app to be conditional based on the loading state of this library. https://www.npmjs.com/package/use-places-autocomplete#option-2-wrap-the-hook-into-a-conditional-component

/** Loads the google api library which is needed by places autocomplete in web */
export const useGoogleMapsApi = () => {
  const [loading, setLoading] = useState(true)

  useEffect(() => {
    if (!isWeb) return setLoading(false)

    loadGoogleMapsApi({ libraries: ['places'], key: env.API_KEY }).then(() => setLoading(false))
  }, [])

  return loading
}

This runs in the entry file, and the actual app UI won't load until this and other necessary initialization tasks are done. That makes it 100% reliable when it comes to using the hook without getting problems loading the library.

With this, initOnMount can be left undefined, because by the time the hook runs in any component, the library must have been loaded during global app initialization.

jeremylanger commented 7 months ago

The Google Maps API no longer requires the callback parameter. You can safely remove this.