({ src, checkForExisting = false, ...attributes })
| 22 | }; |
| 23 | |
| 24 | export default function useScript({ src, checkForExisting = false, ...attributes }) { |
| 25 | // Check whether some instance of this hook considered this src. |
| 26 | let status = src ? scripts[src] : undefined; |
| 27 | |
| 28 | // If requested, check for existing <script> tags with this src |
| 29 | // (unless we've already loaded the script ourselves). |
| 30 | if (!status && checkForExisting && src && isBrowser) { |
| 31 | status = checkExisting(src); |
| 32 | } |
| 33 | |
| 34 | const [loading, setLoading] = useState(status ? status.loading : Boolean(src)); |
| 35 | const [error, setError] = useState(status ? status.error : null); |
| 36 | // Tracks if script is loaded so we can avoid duplicate script tags |
| 37 | const [scriptLoaded, setScriptLoaded] = useState(false); |
| 38 | |
| 39 | useEffect(() => { |
| 40 | // Nothing to do on server, or if no src specified, or |
| 41 | // if script is already loaded or "error" state. |
| 42 | if (!isBrowser || !src || scriptLoaded || error) return; |
| 43 | |
| 44 | // Check again for existing <script> tags with this src |
| 45 | // in case it's changed since mount. |
| 46 | status = scripts[src]; |
| 47 | if (!status && checkForExisting) { |
| 48 | status = checkExisting(src); |
| 49 | } |
| 50 | |
| 51 | // Determine or create <script> element to listen to. |
| 52 | let scriptEl; |
| 53 | |
| 54 | if (status) { |
| 55 | ({ scriptEl } = status); |
| 56 | } else { |
| 57 | scriptEl = document.createElement('script'); |
| 58 | scriptEl.src = src; |
| 59 | |
| 60 | Object.keys(attributes).forEach((key) => { |
| 61 | if (scriptEl[key] === undefined) { |
| 62 | scriptEl.setAttribute(key, attributes[key]); |
| 63 | } else { |
| 64 | scriptEl[key] = attributes[key]; |
| 65 | } |
| 66 | }); |
| 67 | |
| 68 | scripts[src] = { |
| 69 | loading: true, |
| 70 | error: null, |
| 71 | scriptEl, |
| 72 | }; |
| 73 | status = scripts[src]; |
| 74 | } |
| 75 | // `status` is now guaranteed to be defined: either the old status |
| 76 | // from a previous load, or a newly created one. |
| 77 | |
| 78 | const handleLoad = () => { |
| 79 | if (status) status.loading = false; |
| 80 | setLoading(false); |
| 81 | setScriptLoaded(true); |
no test coverage detected