@exabytellc/utils
Version:
EB react utils to make everything a little easier!
71 lines (59 loc) • 2.61 kB
JavaScript
import { useEffect, useState } from "react";
/**
* Custom React hook to dynamically load an external script.
*
* @param {string} id - Unique identifier for the script.
* @param {string} src - The script URL to load.
* @param {Object} [options] - Additional script loading options.
* @param {boolean} [options.async=true] - Whether the script should load asynchronously.
* @param {boolean} [options.defer=true] - Whether the script should defer execution.
* @param {Object} [options.attrs] - Additional attributes to set on the script element.
* @param {boolean} [options.removeOnUnmount=false] - Whether to remove the script when the component unmounts.
*
* @returns {{ loaded: boolean, error: string | null }} - An object containing the script's load state and any error encountered.
*/
export default function useScriptLoader(id, src, options = {}) {
const [loaded, setLoaded] = useState(false);
const [error, setError] = useState(null);
useEffect(() => {
if (!src) return;
// Check if script already exists in the document
if (document.getElementById(`script-loader-${id}`)) {
setLoaded(true);
return;
}
console.log('script', 'start', src);
// Create a new script element
const script = document.createElement("script");
script.id = `script-loader-${id}`;
script.src = src;
script.async = options.async ?? true;
script.defer = options.defer ?? true;
// Apply additional attributes if provided
if (options.attrs) {
for (let key in options.attrs) {
script.setAttribute(key, options.attrs[key]);
}
}
script.onload = () => {
setLoaded(true);
console.log('script', 'fetched', src);
};
script.onerror = () => {
console.log('script', 'failed', src);
setLoaded(true);
setError("Failed to load script!");
};
document.body.append(script);
// Cleanup function (removes script if `removeOnUnmount` is true)
return () => {
if (options.removeOnUnmount) {
const existingScript = document.getElementById(`script-loader-${id}`);
if (existingScript) {
document.body.removeChild(existingScript);
}
}
};
}, [id, options.async, options.attrs, options.defer, options.removeOnUnmount, src]);
return { loaded, error };
}