Loading unnecessary resources can negatively impact the application's performance. Particularly in web applications, we should load only the resources it uses.
This article explains how to load an external script based on a condition. The resource can be any Javascript file, CSS, or JSON.
Loading and unloading script on a button click
In this example, I load and unload the CSS file provided by the w3schools website.
import { useState } from "react"
export const App = () => {
const [stylesLoaded, setStylesLoaded] = useState<boolean>(false)
var link = document.createElement("link");
link.type = "text/css"
link.rel = "stylesheet"
link.href = "https://www.w3schools.com/w3css/4/w3.css"
link.id = "w3schools"
const handleStyles = () => {
if(stylesLoaded){
var externalResource = document.getElementById("w3schools");
externalResource?.parentNode?.removeChild(externalResource);
}
else{
document.head.appendChild(link)
}
setStylesLoaded(prev => !prev)
}
return(
<>
<div className="w3-container">
<div className="w3-panel w3-pale-green">
<p>This message is supposed to have a green background</p>
</div>
<button onClick={handleStyles}>{!stylesLoaded ? "Load Styles" : "Unload Styles" }</button>
</div>
</>
)
}
export default App
Removing script when the component unmounts
The above example is only for illustration purposes. When I navigate away from the component, I must remove the script I loaded conditionally in real-world applications. Otherwise, the script will remain in the DOM until the browser session ends or refreshes.
import { useEffect, useState } from "react"
export const App = () => {
const [stylesLoaded, setStylesLoaded] = useState<boolean>(false)
const handleStyles = () => {
setStylesLoaded(prev => !prev)
}
useEffect (() => {
var link = document.createElement("link");
link.type = "text/css"
link.rel = "stylesheet"
link.href = "https://www.w3schools.com/w3css/4/w3.css"
link.id = "w3schools"
if(stylesLoaded){
document.head.appendChild(link)
}
else{
var externalResource = document.getElementById("w3schools");
externalResource?.parentNode?.removeChild(externalResource);
}
return () => { stylesLoaded && document.head.removeChild(link); }
},[stylesLoaded])
return(
<>
<div className="w3-container">
<div className="w3-panel w3-pale-green">
<p>This message is supposed to have a green background</p>
</div>
<button onClick={handleStyles}>{!stylesLoaded ? "Load Styles" : "Unload Styles" }</button>
</div>
</>
)
}
export default App
Conditional script loading hook
That brings us to the practical re-usability of the functionality I have developed so far. Packaging this code in a React hook is a scalable way to reuse the functionality.
interface ExternalResource {
type: "css" | "javascript"
href: string
id: string
}
export const useExternalResources = (props: ExternalResource): Function[] => {
var link: HTMLLinkElement | HTMLScriptElement
const loadResource = (): void => {
document.head.appendChild(link)
}
const unLoadResource = (): void => {
var externalResource = document.getElementById(props.id);
externalResource?.parentNode?.removeChild(externalResource);
}
if(props.type === "css"){
link = document.createElement("link");
link.type = "text/css"
link.rel = "stylesheet"
link.href = props.href
}
else{
link = document.createElement("script");
link.type = "text/javascript"
link.src = props.href
}
link.id = props.id
return [loadResource, unLoadResource]
}
import { useState } from "react"
import { useExternalResources } from "./components/useCookies"
export const App = () => {
const [stylesLoaded, setStylesLoaded] = useState<boolean>(false)
const [loadStyles, unloadStyles] = useExternalResources({type:"css", href:"https://www.w3schools.com/w3css/4/w3.css", id:"w3school"})
const handleStyles = () => {
!stylesLoaded ? loadStyles() : unloadStyles()
setStylesLoaded(prev => !prev)
}
return(
<>
<div className="w3-container">
<div className="w3-panel w3-pale-green">
<p>This message is supposed to have a green background</p>
</div>
<button onClick={handleStyles}>{!stylesLoaded ? "Load Styles" : "Unload Styles" }</button>
</div>
</>
)
}
export default App