(src: string)
| 2 | import { useState, useEffect } from 'react'; |
| 3 | |
| 4 | export function useScript(src: string) { |
| 5 | const [status, setStatus] = useState<'idle' | 'loading' | 'ready' | 'error'>(src ? 'loading' : 'idle'); |
| 6 | useEffect(() => { |
| 7 | if (!src) { |
| 8 | return; |
| 9 | } |
| 10 | let script = document.querySelector(`script[src="${src}"]`) as HTMLScriptElement; |
| 11 | if (!script) { |
| 12 | script = document.createElement('script'); |
| 13 | script.src = src; |
| 14 | script.async = true; |
| 15 | script.setAttribute('data-status', 'loading'); |
| 16 | document.body.appendChild(script); |
| 17 | const setAttributeFromEvent = (event: Event) => { |
| 18 | script.setAttribute('data-status', event.type === 'load' ? 'ready' : 'error'); |
| 19 | }; |
| 20 | script.addEventListener('load', setAttributeFromEvent); |
| 21 | script.addEventListener('error', setAttributeFromEvent); |
| 22 | } else { |
| 23 | setStatus(script.getAttribute('data-status') as 'idle' | 'loading' | 'ready' | 'error'); |
| 24 | } |
| 25 | const setStateFromEvent = (event: Event) => { |
| 26 | setStatus(event.type === 'load' ? 'ready' : 'error'); |
| 27 | if (event.type === 'error' && script.parentNode) { |
| 28 | script.remove(); |
| 29 | } |
| 30 | }; |
| 31 | script.addEventListener('load', setStateFromEvent); |
| 32 | script.addEventListener('error', setStateFromEvent); |
| 33 | return () => { |
| 34 | if (script) { |
| 35 | script.removeEventListener('load', setStateFromEvent); |
| 36 | script.removeEventListener('error', setStateFromEvent); |
| 37 | } |
| 38 | }; |
| 39 | }, [src]); |
| 40 | return status; |
| 41 | } |
nothing calls this directly
no outgoing calls
no test coverage detected