React useScript Hook
index.html
and script.js
have already been provided in the VM. In general, you only need to add code to script.js
and style.css
.
To dynamically load an external script, use the useState()
hook to create a state variable that stores the load status of the script. Next, use the useEffect()
hook to handle all the logic for loading and unloading the script anytime the src
changes. If no src
value is present, set the status
to 'idle'
and return. Use Document.querySelector()
to check if a <script>
element with the appropriate src
value exists. If no relevant element exists, use Document.createElement()
to create one and give it the appropriate attributes. Use the data-status
attribute as a way to indicate the status of the script, setting it to 'loading'
initially. If a relevant element exists, skip initialization and update the status
from its data-status
attribute. This ensures that no duplicate element will be created. Use EventTarget.addEventListener()
to listen for 'load'
and 'error'
events and handle them by updating the data-status
attribute and the status
state variable. Finally, when the component unmounts, use Document.removeEventListener()
to remove any listeners bound to the element.
Here's an example implementation of the useScript
hook:
const useScript = (src) => {
const [status, setStatus] = React.useState(src ? "loading" : "idle");
React.useEffect(() => {
if (!src) {
setStatus("idle");
return;
}
let script = document.querySelector(`script[src="${src}"]`);
if (!script) {
script = document.createElement("script");
script.src = src;
script.async = true;
script.setAttribute("data-status", "loading");
document.body.appendChild(script);
const setDataStatus = (event) => {
script.setAttribute(
"data-status",
event.type === "load" ? "ready" : "error"
);
};
script.addEventListener("load", setDataStatus);
script.addEventListener("error", setDataStatus);
} else {
setStatus(script.getAttribute("data-status"));
}
const setStateStatus = (event) => {
setStatus(event.type === "load" ? "ready" : "error");
};
script.addEventListener("load", setStateStatus);
script.addEventListener("error", setStateStatus);
return () => {
if (script) {
script.removeEventListener("load", setStateStatus);
script.removeEventListener("error", setStateStatus);
}
};
}, [src]);
return status;
};
Here's an example usage of the useScript
hook:
const script =
"data:text/plain;charset=utf-8;base64,KGZ1bmN0aW9uKCl7IGNvbnNvbGUubG9nKCdIZWxsbycpIH0pKCk7";
const Child = () => {
const status = useScript(script);
return <p>Child status: {status}</p>;
};
const MyApp = () => {
const status = useScript(script);
return (
<>
<p>Parent status: {status}</p>
<Child />
</>
);
};
ReactDOM.createRoot(document.getElementById("root")).render(<MyApp />);
Please click on 'Go Live' in the bottom right corner to run the web service on port 8080. Then, you can refresh the Web 8080 Tab to preview the web page.