Created
May 4, 2020 21:02
-
-
Save felipevlima/d4a0adaa9adbba5829b60b5236f5e65b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Hook | |
import { useEffect, useState } from 'react'; | |
const cachedScripts: any = []; | |
const loadingScripts: any = []; | |
export const useScript = (src: string) => { | |
// Keeping track of script loaded and error state | |
const [state, setState] = useState({ | |
loaded: false, | |
error: false, | |
}); | |
useEffect( | |
() => { | |
// If cachedScripts array already includes src that means another instance ...// If cachedScripts array already includes src that means another instance ... | |
// ... of this hook already loaded this script, so no need to load again. | |
// ... of this hook already loaded this script, so no need to load again. | |
if (cachedScripts.includes(src)) { | |
setState({ | |
loaded: true, | |
error: false, | |
}); | |
} else { | |
let script: any; | |
// Create script only if one is not being loaded | |
if (loadingScripts[src]) { | |
script = loadingScripts[src]; | |
} else { | |
script = document.createElement('script'); | |
script.src = src; | |
script.async = true; | |
// Add script to loadingScripts | |
loadingScripts[src] = script; | |
// Add script to document body | |
document.body.appendChild(script); | |
} | |
// Script event listener callbacks for load and error | |
const onScriptLoad = () => { | |
// Add script to cachedScripts | |
cachedScripts[src] = script; | |
// Remove from loadingScripts | |
delete loadingScripts[src]; | |
setState({ | |
loaded: true, | |
error: false, | |
}); | |
}; | |
const onScriptError = () => { | |
// Remove from loadingScripts we can try loading again | |
delete loadingScripts[src]; | |
script.remove(); | |
setState({ | |
loaded: true, | |
error: true, | |
}); | |
}; | |
script.addEventListener('load', onScriptLoad); | |
script.addEventListener('error', onScriptError); | |
// Add script to document body | |
document.body.appendChild(script); | |
// Remove event listeners on cleanup | |
// and remove script from loadingScripts if not yet loaded | |
return () => { | |
delete loadingScripts[src]; | |
script.removeEventListener('load', onScriptLoad); | |
script.removeEventListener('error', onScriptError); | |
}; | |
} | |
}, | |
[src] // Only re-run effect if script src changes | |
); | |
return [state.loaded, state.error]; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment