ErrorPro / react-google-autocomplete

React components for google places API.
MIT License
474 stars 113 forks source link

Multiple instances of usePlacesAutocompleteService on same Page / Component gives error #236

Open malikk908 opened 4 months ago

malikk908 commented 4 months ago

I have an AddressSuggestion.js component which uses usePlacesAutocompleteService like this

import usePlacesService from "react-google-autocomplete/lib/usePlacesAutocompleteService";

const {
        placePredictions,
        getPlacePredictions,
        isPlacePredictionsLoading,
    } = usePlacesService({
        apiKey: process.env.REACT_APP_MAPS_API_KEY ?
            `${process.env.REACT_APP_MAPS_API_KEY}&loading=async` :
            "keyUnavailable",
        debounce: 500
    });

the problem is if I am trying to use the same component two times on a single page (single parent component), then I am getting this Uncaught runtime error:

usePlacesAutocompleteService.js:110 Uncaught (in promise) 
TypeError: Cannot read properties of undefined (reading 'AutocompleteService')
    at buildService (usePlacesAutocompleteService.js:110:1)
    at usePlacesAutocompleteService.js:118:1

although the component seems to work fine (in development though, haven't checked in production)

malikk908 commented 4 months ago

As a workwround, I no longer provide the apiKey prop to usePlacesService and iinstead load the maps api through a custom hook which looks like this:

useGoogleMapsApi.js

import { useEffect, useState } from 'react';

function useGoogleMapsApi() {
  const [isApiLoaded, setApiLoaded] = useState(false);

  useEffect(() => {
    const loadGoogleMapsApi = () => {
      if (!window.google) {
        const script = document.createElement('script');
        script.src = `https://maps.googleapis.com/maps/api/js?key=${process.env.REACT_APP_MAPS_API_KEY}&libraries=places&loading=async`;
        script.async = true;
        script.defer = true;
        script.addEventListener('load', () => {
          // The Google Maps API has been loaded and is now available
          setApiLoaded(true);
        });
        document.body.appendChild(script);
      } else {
        setApiLoaded(true);
      }
    };

    loadGoogleMapsApi();
  }, []);

  return isApiLoaded;
}

export default useGoogleMapsApi;

Now load it in any components like this:

function MyComponent() {
 const isLoaded = useGoogleMapsApi();

 return (
 {isLoaded && <AddressSuggestion/>}
 )
}

The AddressSuggestion.js component uses the usePlacesService.js hook like this:

import usePlacesService from "react-google-autocomplete/lib/usePlacesAutocompleteService";

const {
        placePredictions,
        getPlacePredictions,
        isPlacePredictionsLoading,
    } = usePlacesService({        
        debounce: 500
    });