Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Loader not downloading the google map script post deleting window.google object on component unmount #358

Closed
AkashGoenka opened this issue Aug 25, 2021 · 8 comments

Comments

@AkashGoenka
Copy link

AkashGoenka commented Aug 25, 2021

I have used the js-api-loader to develop a location search field which would give a list of suggestions (using the autocomplete service) when the user begins to type in the search box. This functionality is something that is not going to be used often. So, we delete the script and the window.google object on component unmount. However, we notice that on revisiting the page where this search field is located, the Loader does not make a call to refetch the google map script.

Environment details

  1. Specify the API at the beginning of the title
    places

  2. OS type and version -
    All Platforms, Windows, Mac and Linux. Desktop and Mobile as well

  3. Library version and other environment information
    "@googlemaps/js-api-loader": "~1.12.1"
    "react": "~17.0.2",
    "next": "~10.1.3",

Since we use NextJS with server side rendering enabled, the window object is available only in functions that run on the client side. Code sample below

Code example

# example 
const GOOGLE_MAP_SCRIPT_ID = 'googleMapScriptCustom';
/**
   * This hook is to cleanup the google map script and the google object once this component is unmounted
   */
  useEffect(() => {
    return () => {
      const gMapScript = document.querySelector(`#${GOOGLE_MAP_SCRIPT_ID}`);
      if (gMapScript) {
        gMapScript.remove();
        delete window.google;
      }
    };
  }, []);

 /**
   * This useEffect is used to load the Google Map Javscript API
 */
  useEffect(() => {
      new Loader({
        apiKey: googleMapsApiKey,
        id: GOOGLE_MAP_SCRIPT_ID,
        version: 'weekly',
        libraries: ['places']
      }).load();
  }, [googleMapsApiKey]);

 /**
   * This callback function is called to retrieve the location search results and is triggered on the change event in the input field
   */
  const getLocations = useCallback(async queryText => {
    if (queryText && window.google) {
      const autoCompleteServiceResults = await new window.google.maps.places.AutocompleteService().getPlacePredictions(
        {
          input: queryText,
          types: ['(cities)']
        }
      );
      setPlaces(getLocationList(autoCompleteServiceResults?.predictions) ?? []);
      setShowSuggestions(true);
    }
  }, []);
  

The above is not the complete piece of code. It is just given for a rough estimation of how we are loading and deleting the google map js script on mounting and unmounting.

Please let me know if you need any more information

@jpoehnelt
Copy link
Contributor

First, I would not recommend this pattern of deleting and reloading as it will result in double billing.

If you want this behavior, you can try using the private loader.reset() method. duplicate of #100

@jpoehnelt
Copy link
Contributor

This hook is to cleanup the google map script and the google object once this component is unmounted

Can you elaborate on this use case and why it is necessary?

@AkashGoenka
Copy link
Author

In my application, the location field is used on a page that is not going to be used frequently. Once the user leaves that page, we don't want the google script and the object to persist as it most likely not going to be used as long as the user is on the application. This is why we are doing it as a part of the cleanup function.

loader.reset() doesn't delete the window.google object is what i've observed. And can you elaborate on the double billing part please, i was of the understanding that billing happens on the number of requests that we using the API key.

@AkashGoenka
Copy link
Author

AkashGoenka commented Aug 25, 2021

@jpoehnelt Is there a better way that you think of where we can achieve the expected outcome.

I just tried and see that i can get the api to load. It's just that i have to call loader.reset() before calling loader.load(). But i don't want this to affect my billing.

@jpoehnelt
Copy link
Contributor

Double billing would only be in cases where you create a google.maps.Map instance combined with reloading the entire API. That might not be the case here.

we don't want the google script and the object to persist as it most likely not going to be used

Why does this matter?

Would probably want this order of steps:

// cleanup
delete window.google;
loader.deleteScript();
loader.reset();

// later
loader.load();

@AkashGoenka
Copy link
Author

The idea to delete the script and the google object was because of the reason that we wanted to unload the effect that we are making use of once the component is unmounted, as most likely it is not going to be used again. There were no other strong reasons. But giving some more thought to it, i think that it's better to conditionally create a new instance of loader only the window.google object doesn't exist. So we will go ahead with that approach.

In future, when #100 is implemented, we will update our code. I'll close this, thanks for the prompt response @jpoehnelt .

@jpoehnelt
Copy link
Contributor

i think that it's better to conditionally create a new instance of loader only the window.google

The Loader class acts as a singleton and will do this for you so long as you pass the same settings (key, libraries, etc).

@jpoehnelt jpoehnelt removed their assignment Jun 22, 2022
@wlbksy
Copy link

wlbksy commented Jan 18, 2023

I have a user case for region dynamic change.
Different countries disagree on territory.
So user-side region dynamic change is preferred , in order to avoid law-breaking map usage in their local country.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants