1 |
|
2 | import * as React from 'react'
|
3 | import invariant from 'invariant'
|
4 |
|
5 | import { isBrowser } from './utils/isbrowser'
|
6 | import { injectScript } from './utils/injectscript'
|
7 | import { preventGoogleFonts } from './utils/prevent-google-fonts'
|
8 | import { makeLoadScriptUrl, LoadScriptUrlOptions } from './utils/make-load-script-url'
|
9 |
|
10 | import { defaultLoadScriptProps } from './LoadScript'
|
11 |
|
12 | export interface UseLoadScriptOptions extends LoadScriptUrlOptions {
|
13 | id?: string
|
14 | preventGoogleFontsLoading?: boolean
|
15 | }
|
16 |
|
17 | let previouslyLoadedUrl: string
|
18 |
|
19 | export function useLoadScript({
|
20 | id = defaultLoadScriptProps.id,
|
21 | version = defaultLoadScriptProps.version,
|
22 | googleMapsApiKey,
|
23 | googleMapsClientId,
|
24 | language,
|
25 | region,
|
26 | libraries,
|
27 | preventGoogleFontsLoading,
|
28 | channel,
|
29 | }: UseLoadScriptOptions): {
|
30 | isLoaded: boolean
|
31 | loadError: Error | undefined
|
32 | url: string
|
33 | } {
|
34 | const isMounted = React.useRef(false)
|
35 | const [isLoaded, setLoaded] = React.useState(false)
|
36 | const [loadError, setLoadError] = React.useState<Error | undefined>(undefined)
|
37 |
|
38 | React.useEffect(function trackMountedState() {
|
39 | isMounted.current = true
|
40 | return (): void => {
|
41 | isMounted.current = false
|
42 | }
|
43 | }, [])
|
44 |
|
45 | React.useEffect(
|
46 | function applyPreventGoogleFonts() {
|
47 | if (isBrowser && preventGoogleFontsLoading) {
|
48 | preventGoogleFonts()
|
49 | }
|
50 | },
|
51 | [preventGoogleFontsLoading]
|
52 | )
|
53 |
|
54 | React.useEffect(
|
55 | function validateLoadedState() {
|
56 | if (isLoaded) {
|
57 | invariant(
|
58 | !!window.google,
|
59 | 'useLoadScript was marked as loaded, but window.google is not present. Something went wrong.'
|
60 | )
|
61 | }
|
62 | },
|
63 | [isLoaded]
|
64 | )
|
65 |
|
66 | const url = makeLoadScriptUrl({
|
67 | version,
|
68 | googleMapsApiKey,
|
69 | googleMapsClientId,
|
70 | language,
|
71 | region,
|
72 | libraries,
|
73 | channel,
|
74 | })
|
75 |
|
76 | React.useEffect(
|
77 | function loadScriptAndModifyLoadedState() {
|
78 | if (!isBrowser) {
|
79 | return
|
80 | }
|
81 |
|
82 | function setLoadedIfMounted(): void {
|
83 | if (isMounted.current) {
|
84 | setLoaded(true)
|
85 | previouslyLoadedUrl = url
|
86 | }
|
87 | }
|
88 |
|
89 | if (window.google && previouslyLoadedUrl === url) {
|
90 | setLoadedIfMounted()
|
91 | return
|
92 | }
|
93 |
|
94 | injectScript({ id, url })
|
95 | .then(setLoadedIfMounted)
|
96 | .catch(function handleInjectError(err) {
|
97 | if (isMounted.current) {
|
98 | setLoadError(err)
|
99 | }
|
100 | console.warn(`
|
101 | There has been an Error with loading Google Maps API script, please check that you provided correct google API key (${googleMapsApiKey ||
|
102 | '-'}) or Client ID (${googleMapsClientId || '-'})
|
103 | Otherwise it is a Network issue.
|
104 | `)
|
105 | console.error(err)
|
106 | })
|
107 | },
|
108 | [id, url]
|
109 | )
|
110 |
|
111 | const prevLibraries = React.useRef<undefined | string[]>()
|
112 |
|
113 | React.useEffect(
|
114 | function checkPerformance() {
|
115 | if (prevLibraries.current && libraries !== prevLibraries.current) {
|
116 | console.warn(
|
117 | 'Performance warning! LoadScript has been reloaded unintentionally! You should not pass `libraries` prop as new array. Please keep an array of libraries as static class property for Components and PureComponents, or just a const variable outside of component, or somewhere in config files or ENV variables'
|
118 | )
|
119 | }
|
120 | prevLibraries.current = libraries
|
121 | },
|
122 | [libraries]
|
123 | )
|
124 |
|
125 | return { isLoaded, loadError, url }
|
126 | }
|