@exabytellc/utils
Version:
EB react utils to make everything a little easier!
70 lines (58 loc) • 2.6 kB
JavaScript
import { useEffect, useState } from "react";
/**
* Custom React hook to dynamically load an external CSS file or other linked resources.
*
* @param {string} id - Unique identifier for the link element.
* @param {string} href - The URL of the resource to load.
* @param {Object} [options] - Additional link loading options.
* @param {string} [options.rel="stylesheet"] - The relationship between the document and the linked resource.
* @param {string} [options.type="text/css"] - The MIME type of the linked resource.
* @param {string} [options.media="all"] - The media attribute for the linked resource.
* @param {Object} [options.attrs] - Additional attributes to set on the link element.
* @param {boolean} [options.removeOnUnmount=false] - Whether to remove the link when the component unmounts.
*
* @returns {{ loaded: boolean, error: string | null }} - An object containing the link's load state and any error encountered.
*/
export default function useLinkLoader(id, href, options = {}) {
const [loaded, setLoaded] = useState(false);
const [error, setError] = useState(null);
useEffect(() => {
if (!href) return;
// Check if the link already exists in the document
if (document.getElementById(`link-loader-${id}`)) {
setLoaded(true);
return;
}
console.log('link', 'start', href);
// Create a new link element
const link = document.createElement("link");
link.id = `link-loader-${id}`;
link.href = href;
link.rel = options.rel ?? "stylesheet";
link.type = options.type ?? "text/css";
link.media = options.media ?? "all";
// Apply additional attributes if provided
if (options.attrs) {
for (let key in options.attrs) {
link.setAttribute(key, options.attrs[key]);
}
}
link.onload = () => {
setLoaded(true);
console.log('link', 'fetched', href);
};
link.onerror = () => {
console.log('link', 'failed', href);
setLoaded(true);
setError("Failed to load link!");
};
document.head.appendChild(link);
// Cleanup function (removes link if `removeOnUnmount` is true)
return () => {
if (options.removeOnUnmount && document.head.contains(link)) {
document.head.removeChild(link);
}
};
}, [id, href, options]);
return { loaded, error };
};