Open marnixhoh opened 3 years ago
Also having this issue
watching...we also use @react-google-maps/api
for the useLoadScript
feature:
const { isLoaded: isGoogleLoaded } = useLoadScript({
googleMapsApiKey: process.env.NEXT_PUBLIC_GOOGLE_API_KEY,
libraries: LIBRARIES,
});
Are both libs needed?
"@react-google-maps/api": "^2.2.0",
"google-map-react": "^2.1.9",
Same issue here
I'm also getting this warning because I'm loading the Google Maps API via a script tag in the header of every page of my application:
<script
type="text/javascript"
src={`https://maps.googleapis.com/maps/api/js?key=${process.env.GOOGLE_API_KEY!}&libraries=places`}
/>
I'm doing this because I also need the API for react-google-places-autocomplete. And, this script tag is one method they suggest for loading the API.
My problem is that I also need to use the onGoogleApiLoaded
function to center the map once loaded, and it's not clear if that would work if I loaded the Google Maps API through the script tag instead of this library.
Does anyone actually know what issues this warning is alluding to? If I have two different components that are doing different things and only communicating to each other through state in my app, is there really a risk of things breaking by having both use different instances of the API? Or is it even two instances or one component overriding the version of the API the other component is using? If that's the case I would just need to make sure both components expect the same version of the Google Maps API and I can safely ignore this warning right? I have yet to notice any issues in my application with this warning but I don't know if I'm sitting on a ticking time bomb.
Also FYI, there's already been a lot of discussion about this issue in https://github.com/google-map-react/google-map-react/issues/954. The author says that this issue was fixed in 2.1.9 but it seems like a lot of people are still reporting the warning.
I got the same issue when using this lib with react-google-places-autocomplete
Here is my workaround to hide the warning but not recommend
useEffect(() => { if (typeof google !== 'object') { const result = useJsApiLoader({ googleMapsApiKey: COMMON_CONFIG.googleMapsApiKey, }); setIsMapLoaded(result.isLoaded); } else { setIsMapLoaded(true); } }, []);
@jpoehnelt Could you check on this bug? π
I haven't seen anything showing a bug here. It seems that most of these issues except maybe the first comment are all mixing different methods of loading the API, leading to the warning. Perhaps the first comment could be related to how the application is bundled and and not using the singleton??
I have resolved it by using a single API now. We migrated all to react-google-maps-api
EDITED:
I realized this question is asking specifically about the js-api-loader. In their docs it states you can pass id prop which will prevent double loading the script. The below script will only load google maps if it was not previously loaded
const loader = new Loader({
apiKey: "",
id: "__googleMapsScriptId",
version: "weekly",
libraries: ["places"]
});
I had the same issue, what I ended up doing is dynamically loading the script when the page is mounted. The below functions will check if the script is loaded and only load it if it doesn't already exist.
function setupCallback(script: any, callback: () => void) {
if (script.readyState) {
script.onreadystatechange = function () {
if (script.readyState === 'loaded' || script.readyState === 'complete') {
script.onreadystatechange = null
callback()
}
}
} else {
script.onload = () => {
callback()
}
}
}
export const loadScript = (url: string, callback: () => void, id: string) => {
let script: any
if (document.getElementById(id)) {
// If the script already exists then add the new callback to the existing one
script = document.getElementById(id)
const oldFunc = script.onload
setupCallback(script, () => {
oldFunc && oldFunc()
callback()
})
} else {
// If the script doesn't exists then create it
script = document.createElement('script')
script.type = 'text/javascript'
script.src = url
script.setAttribute('id', id)
setupCallback(script, callback)
document.getElementsByTagName('head')[0].appendChild(script)
}
}
Then it can be called with
loadScript(
`https://maps.googleapis.com/maps/api/js?key=API_KEY&libraries=places`,
callbackFunction,
'__googleMapsScriptId',
)
@khevamann Could you submit a PR in our library so we could handle this? Seems that @jpoehnelt's fix was missing that.
@itsmichaeldiego I looked into it and it looks like it already works as is. All additional props from bootstrapURLKeys are automatically passed into the loader, and js-api-loader accepts an id like I mentioned above. So the code below works correctly. I put in a PR to update this in the types definition. Is there somewhere I should add this to documentation.
<GoogleMapReact
bootstrapURLKeys={{ key: API_KEY, libraries: ['places'], id: 'CUSTOM_SCRIPT_ID' }}
defaultCenter={defaultProps.center}
defaultZoom={defaultProps.zoom}
/>
Then to use google maps script anywhere else on the page, you can use
const loader = new Loader({
apiKey: "",
id: "__googleMapsScriptId",
version: "weekly",
libraries: ["places"]
});
Perfect @khevamann, thank you so much!
Is it just me or is this fix gone again? I have attached a screenshot of the type file... and I've got version 2.1.10
@dillonharless18 Please share you app code. You likely have the Google Maps API loaded outside of this component library.
EDITED:
Non-issue... messed up my center property. Still strange that I don't see ID in the type file for google-map-react, but it seems to be working. Let me know if I should just delete these comments @jpoehnelt
Thanks for the quick response @jpoehnelt
Yeah I loaded it once before using @googlemaps/js-api-loader... I might not understand it well enough, but I wouldn't think that should mess with the type files for google-map-react.
This happens first. It's imported and run by a file early in the business logic to geocode an address.
import { Loader } from '@googlemaps/js-api-loader';
const loadScript = async () => {
const loader = new Loader({
apiKey: process.env.REACT_APP_GOOGLE_MAPS_API_KEY
// version: 'beta',
id: "__googleMapsScriptId",
});
await loader.load();
};
export const geo = async(address: string) => {
try {
await loadScript();
const geocoder = new google.maps.Geocoder();
const results = await geocoder.geocode({ address: address });
return results
} catch (e) {
console.error(`There was an error: ${JSON.stringify(e, null, 2)}`)
}
}
export async function reverseGeo(
lat: number, long: number
): Promise<string> {
await loadScript();
const geocoder = new google.maps.Geocoder();
const latlng = {
lat: lat,
lng: long,
};
try {
const { results } = await geocoder.geocode({ location: latlng });
if (results && results[0]) {
return results[0].formatted_address;
}
} catch (e) {
// handle exception
}
throw new TypeError('Zero result or reverse geo Failed');
}
I then try to render a map later on in the app using this file
import React, { useContext, useRef, useEffect, useState } from 'react';
import GoogleMapReact from 'google-map-react';
import { useTranslation } from 'react-i18next';
import { DemographicsContext } from '../context/DemographicsContext';
import { ReactComponent as CC_YouMapMarker } from '../svg/CC_YouMapMarker.svg';
import { ReactComponent as CC_PODMapMarker } from '../svg/CC_PODMapMarker.svg';
import { DisasterContext } from '../context/DisasterContext';
import { StyledExplcitGrid, StyledPageBodyText } from './ReusableStyledComponents';
interface IPOD {
OrganizationName: string,
PODID: string,
PODLatitude: string,
PODLongitude: string,
PODDescription: string
}
interface IMapMarker {
lat: number,
lng: number,
type: string,
id: string,
popupCoords?: {lat: number, lng: number},
handleMarkerClick: Function,
markerState: any,
POD?: IPOD
}
const MapMarker: React.FC<IMapMarker> = ({ type, id, handleMarkerClick, POD }) => {
const { t, i18n } = useTranslation();
const onMarkerClick = (e) => {
if ( type === "POD" ) {
e.preventDefault();
handleMarkerClick(e, null, "POD", POD);
} else {
e.preventDefault();
handleMarkerClick(e, null, "USER");
}
}
return (
<StyledExplcitGrid
id={id}
width={'fit-content'}
onClick={(e) => onMarkerClick(e)}
>
{
type === 'USER' &&
<>
<CC_YouMapMarker pointerEvents="none"/>
<StyledPageBodyText fontSize={"1em"} fontWeight={"800"}>{t("YOU")}</StyledPageBodyText>
</>
}
{
type === 'POD' &&
<>
<CC_PODMapMarker pointerEvents="none" />
<StyledPageBodyText fontSize={"1em"} fontWeight={"800"}>{POD?.PODDescription}</StyledPageBodyText>
</>
}
</StyledExplcitGrid>
)
}
interface ISimpleMap {
apiKey: string,
center?: any,
zoom?: number,
handleMarkerClick: Function,
markerState: any,
PODS?: any
}
const SimpleMap: React.FC<ISimpleMap> = (props: any) => {
const { handleMarkerClick, markerState, PODS } = props;
const demographicsContext = useContext(DemographicsContext);
const { homeLatLng } = demographicsContext;
const disasterContext = useContext(DisasterContext);
const apiKey = props.apiKey ? props.apiKey : "KEY NOT FOUND IN SIMPLE MAP";
const podType: string = "POD";
let center = {...homeLatLng};
let zoom = props.zoom ? props.zoom : 10
return (
<>
<div style={{ height: '45vh', width: '100%' }}>
<GoogleMapReact
options={{
styles: [
{
"elementType": "labels",
"stylers": [
{
"visibility": "off"
}
]
},
{
"featureType": "administrative.locality",
"stylers": [
{
"visibility": "on"
}
]
},
{
"featureType": "administrative.neighborhood",
"stylers": [
{
"visibility": "on"
}
]
},
{
"featureType": "administrative.province",
"stylers": [
{
"visibility": "on"
}
]
},
{
"featureType": "road",
"stylers": [
{
"visibility": "on"
}
]
}
]
}}
bootstrapURLKeys={{ key: apiKey }}
center={center}
zoom={zoom}
yesIWantToUseGoogleMapApiInternals
// onGoogleApiLoaded={initGeocoder}
>
{
PODS.map((pod, i) => {
return(
<MapMarker
key={pod.PODID.concat(`-key-${i}`)}
lat={pod.PODLatitude}
lng={pod.PODLongitude}
type={podType}
id={pod.PODID.concat(`-${i}`)}
// popupCoords={pod.center}
handleMarkerClick={handleMarkerClick}
markerState={markerState}
POD={{...pod}}
/>
)
})
}
<MapMarker
lat={center.lat}
lng={center.lng}
type="USER"
// onMarkerClick={handleMarkerClick}
id={"USER"}
handleMarkerClick={handleMarkerClick}
markerState={markerState}
>
</MapMarker>
</GoogleMapReact>
</div>
</>
);
}
export default SimpleMap;
Problem is the map is blank... but the markers show. I put a screenshot below. The map was showing just fine before I started using the geocoding API earlier in the app flow. Fwiw when I first introduced importing the geocoding API, I was getting an error on the map screen that said something like "can't import API a second time with different parameters" so I resolved the difference in the parameters when google-map-react loads the API and the error went away, but left me with the blank map.
Im having a similar error as the above comment. Using PlacesAutocomplete
which has it's own desires for loading things and seems to be conflicting with google-map-react
.
Like the above poster, my markers appear but not the map.
@Snarik I also have a same problem, whichever load first, it will work. If I open PlaceAutocomplete first. then its work fine. then google-map-react not work. if I load google-map-react, then PlaceAutoComplete not work.
did you find any solution to this.
Solution Found
Do not add key here
<GooglePlacesAutocomplete
apiKey={process.env.REACT_APP_GOOGLE_MAP_KEY} // do not add this line at all.
/>
instead add script in public/index.html file
Make sure to add Library=places
in the script
This way whenever you open the placepicker page, it will not try to initialise api key again. bcz its already loaded.
Describe the bug π
I use
@googlemaps/js-api-loader
explicitly on a page wheregoogle-map-react
is not used. However, when I navigate between this page and one that does usegoogle-map-react
(or vice-versa) I get the following warning:Google Maps already loaded outside @googlemaps/js-api-loader. This may result in undesirable behavior as options and script parameters may not match.
I noticed that I can easily prevent this warning from showing by conditionally loading Google Maps on the page that explicitly uses
@googlemaps/js-api-loader
by checking to see ifwindow.google
exists or not (see minimal reproducible example below). However, I couldn't find a way to do something similar withgoogle-map-react
?Any help or suggestions would be greatly appreciated!
To Reproduce π Minimal reproducible example:
File A.js (conditionally uses
@googlemaps/js-api-loader
):File B.js (uses
google-map-react
)Environment: