@react-google-maps/api
Version:
React.js Google Maps API integration
77 lines (65 loc) • 2.09 kB
text/typescript
import { isBrowser } from './isbrowser'
interface WindowWithGoogleMap extends Window {
initMap?: () => void
}
interface InjectScriptArg {
url: string
id: string
}
export const injectScript = ({ url, id }: InjectScriptArg): Promise<any> => {
if (!isBrowser) {
return Promise.reject(new Error('document is undefined'))
}
return new Promise(function injectScriptCallback(resolve, reject) {
const existingScript = document.getElementById(id) as HTMLScriptElement | undefined
const windowWithGoogleMap: WindowWithGoogleMap = window
if (existingScript) {
// Same script id/url: keep same script
const dataStateAttribute = existingScript.getAttribute('data-state')
if (existingScript.src === url && dataStateAttribute !== 'error') {
if (dataStateAttribute === 'ready') {
return resolve(id)
} else {
const originalInitMap = windowWithGoogleMap.initMap
const originalErrorCallback = existingScript.onerror
windowWithGoogleMap.initMap = function initMap() {
if (originalInitMap) {
originalInitMap()
}
resolve(id)
}
existingScript.onerror = function(err) {
if (originalErrorCallback) {
originalErrorCallback(err)
}
reject(err)
}
return
}
}
// Same script id, but either
// 1. requested URL is different
// 2. script failed to load
else {
existingScript.remove()
}
}
const script = document.createElement('script')
script.type = 'text/javascript'
script.src = url
script.id = id
script.async = true
script.onerror = function onerror(err) {
script.setAttribute('data-state', 'error')
reject(err)
}
windowWithGoogleMap.initMap = function onload() {
script.setAttribute('data-state', 'ready')
resolve(id)
}
document.head.appendChild(script)
}).catch(err => {
console.error('injectScript error: ', err)
throw err
})
}