JustFly1984 / react-google-maps-api

React Google Maps API
MIT License
1.76k stars 426 forks source link

You have included the Google Maps JavaScript API multiple times on this page. This may cause unexpected errors. #3199

Open jhoriascos opened 1 year ago

jhoriascos commented 1 year ago

Hi, I'm new to React and Ionic

I'm working with Google Maps so I am using:

My Environment

os: Mac, Android, IOS

node --version: 14.21.1

react version: 18.2.0

Please provide an explanation of the issue

The error I'm getting is: You have included the Google Maps JavaScript API multiple times on this page. This may cause unexpected errors.

Ofc, once the map is removed from the same page - the autocomplete works properly!. Also, the map component works both with the autocomplete and without it.

I need to include the two libraries in the same page, can someone help me or do you have an example of how to implement them?

I am sharing the basic example code I am using to test the integration of the two libraries on the same page.

` import React, {useState} from "react";

import { IonSearchbar } from "@ionic/react";
import { IonList } from "@ionic/react";
import { IonItem } from "@ionic/react";
import { searchCircle } from "ionicons/icons";

import useGoogle from "react-google-autocomplete/lib/usePlacesAutocompleteService";
import { GoogleMap, LoadScript } from '@react-google-maps/api';
import { useLoadScript } from '@react-google-maps/api'

const MyMap: React.FC = ({}) => {

    const {
        placePredictions,
        getPlacePredictions,
        isPlacePredictionsLoading,
      } = useGoogle({
        apiKey: API_KEY_GOOGLE_MAPS,
      });
      const [value, setValue] = useState("");

    return(
        <>
        <IonSearchbar 
            searchIcon={searchCircle} 
            placeholder="Ingrese un lugar"
            debounce={1000}
            value={value}
            onIonChange={(ev) => {
                getPlacePredictions({ input: ev.target.value});
                setValue(ev.target.value);
            }}
        ></IonSearchbar>

        <IonList>
            {placePredictions.map(
                place => (
                    <IonItem onClick={() => setValue(place.description)}>
                        {place.description}
                    </IonItem>
                )
            )}
        </IonList>

        <LoadScript
        googleMapsApiKey={API_KEY_GOOGLE_MAPS}
      >
        <GoogleMap

          center={{
            lat: -3.745,
            lng: -38.523
          }}
          zoom={10}
        >
          { /* Child components, such as markers, info windows, etc. */ }
          <></>
        </GoogleMap>
      </LoadScript>
      </>
    );
}

export default MyMap;

`

Basic implementation of incorrect behavior in codesandbox.com

Captura de Pantalla 2023-02-14 a la(s) 9 51 58 a  m

https://codesandbox.io/s/mutable-hooks-3cxbcf?file=/src/App.tsx

Yrll21 commented 1 year ago

I can see that you are using useGoogle and LoadScript together, this could cause your app to render multiple Javascript script tags, since both of them also asks for your API key. Make sure that you are only using one. react-google-maps/api library actualy does have its own <Autocomplete /> component so you can use it to use LoadScript alone.

SeanMH8911 commented 1 year ago

I am getting the same error. I have my map and search box in separate components, as I need the searchBox to auto-fill an address form. The map is then displayed in another component displaying venue data. I also have another map component displaying on the main page with all the venue markers. Is there no way of sharing the api to reduce api calls?

riccoutinho commented 1 year ago

Hey @jhoriascos. I was having the same issue and could solve it going through a different way.
First, I did not use the <LoadScript /> component. Instead of using it, I called the useLoadScript hook as below:

  const { isLoaded } = useJsApiLoader({
    id: '__googleMapsScriptId',
    googleMapsApiKey: "GOOGLE_API_KEY",
    libraries: googleMapsLibraries,
  })

The googleMapsLibraries is a constant declared outside the React component to avoid the performance problem that was warned on the console.

const googleMapsLibraries = ['places']

In my case, it seems that by setting the libraries option on the useJsApiLoader hook, the loader of react-google-places-autocomplete could recognize that it is already loaded and doesn't create a second instance. With that, my problem was solved.

Since I didn't use the LoadScript, my component looked something like this:

const googleMapsLibraries = ['places']

export const Map = () => {
  const { isLoaded } = useJsApiLoader({
    id: '__googleMapsScriptId',
    googleMapsApiKey: "GOOGLE_API_KEY",
    libraries: googleMapsLibraries,
  })

  const center = { lat: latitude, lng: longitude }
  const [map, setMap] = useState<GoogleMap['state']['map']>(null)

  const onLoad = useCallback(() => {
    const bounds = new window.google.maps.LatLngBounds(center)

    map?.fitBounds(bounds)
    setMap(map)
  }, [])

  const onUnmount = useCallback(() => {
    setMap(null)
  }, [])

  return isLoaded ? (
      <GoogleMap
        onLoad={onLoad}
        onUnmount={onUnmount}
      >
         ...
      </GoogleMap>
  ) : (
    <>Error</>
  )
}