js-api-loader
js-api-loader copied to clipboard
Maps: @googlemaps/js-api-loader importLibrary fails sometimes even after multiple tries.
I am using the @googlemaps/js-api-loader
package in a React app. I am noticing that for some users the map libraries fail to load even after multiple retries.
Code:
import React, {createContext, useContext, useEffect, useState} from 'react';
import {Loader} from '@googlemaps/js-api-loader';
const GoogleMapsContext = createContext({
googleMapsLoaded: false,
googleMapsLibraries: null,
});
const MAX_RETRIES = 3;
const loadLibraries = (loader, retries = MAX_RETRIES) => {
return Promise.allSettled([
loader.importLibrary('core'),
loader.importLibrary('maps'),
loader.importLibrary('marker'),
loader.importLibrary('streetView'),
loader.importLibrary('geocoding'),
loader.importLibrary('places'),
loader.importLibrary('routes'),
]).then(results => {
const loadedLibraries = results
.filter(result => result.status === 'fulfilled')
.map(result => (result as PromiseFulfilledResult<any>).value);
const failedLibraries = results.filter(
result => result.status === 'rejected'
);
if (failedLibraries.length > 0) {
if (retries === 0) {
throw new Error(
`Failed to load ${failedLibraries.length} libraries after ${MAX_RETRIES} attempts.`
);
} else {
return loadLibraries(loader, retries - 1);
}
}
return loadedLibraries;
});
};
const GoogleMapsProvider = ({apiKey, children}) => {
const [googleMapsLoaded, setGoogleMapsLoaded] = useState(false);
const [googleMapsLibraries, setGoogleMapsLibraries] = useState(null);
useEffect(() => {
let isCancelled = false;
const loader = new Loader({
apiKey,
version: 'weekly',
});
loadLibraries(loader)
.then(libs => {
if (!isCancelled) {
setGoogleMapsLibraries({
core: libs[0],
maps: libs[1],
marker: libs[2],
streetView: libs[3],
geocoding: libs[4],
places: libs[5],
routes: libs[6],
});
setGoogleMapsLoaded(true);
}
})
.catch(error => {
console.error({
error,
message: 'GoogleMapsProvider: Error loading Google Maps libraries',
});
});
return () => {
isCancelled = true;
};
}, [apiKey]);
if (typeof window === 'undefined') {
return children;
}
return (
<GoogleMapsContext.Provider
value={{
googleMapsLoaded,
googleMapsLibraries,
}}
>
{children}
</GoogleMapsContext.Provider>
);
};
const useGoogleMapsLibraries = () => {
return useContext(GoogleMapsContext);
};
export {GoogleMapsProvider, useGoogleMapsLibraries};