Skip to content

Instantly share code, notes, and snippets.

@nkint
Created October 17, 2019 10:37
Show Gist options
  • Save nkint/25e5368f12278e84983f44259d69ddf2 to your computer and use it in GitHub Desktop.
Save nkint/25e5368f12278e84983f44259d69ddf2 to your computer and use it in GitHub Desktop.
useScript
import { useState, useEffect } from 'react';
import { noop } from 'lodash';
/** original code from
* https://usehooks.com/useScript/
* https://stackoverflow.com/a/51242436/433685
* */
function isScriptLoaded(src: string) {
return document.querySelector('script[src="' + src + '"]') ? true : false;
}
let cachedScripts: string[] = [];
export function useScript(src: string, onLoad: () => void = noop) {
// 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 ...
// ... of this hook already loaded this script, so no need to load again.
const alreadyLoaded = isScriptLoaded(src);
if (cachedScripts.includes(src) || alreadyLoaded) {
setState({
loaded: true,
error: false,
});
onLoad();
} else {
cachedScripts.push(src);
// Create script
let script = document.createElement('script');
script.src = src;
script.async = true;
// Script event listener callbacks for load and error
const onScriptLoad = () => {
setState({
loaded: true,
error: false,
});
onLoad();
};
const onScriptError = () => {
// Remove from cachedScripts we can try loading again
const index = cachedScripts.indexOf(src);
if (index >= 0) cachedScripts.splice(index, 1);
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
return () => {
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