-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathuseScript.js
55 lines (54 loc) · 1.87 KB
/
useScript.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import { useState, useEffect } from "react";
export default function useScript(src) {
// status: "idle", "loading", "ready", "error"
const [status, setStatus] = useState(src ? "loading" : "idle");
useEffect(
() => {
// Wait if source is not ready
if (!src) {
setStatus("idle");
return;
}
// Check if script exists by src
let script = document.querySelector(`script[src="${src}"]`);
if (!script) {
// If not override it with script tag
script = document.createElement("script");
script.src = src;
script.async = true;
script.setAttribute("data-status", "loading");
// Append script to body
document.body.appendChild(script);
// Store status in attribute on script
// This can be read by other instances of this hook
const setAttributeFromEvent = (event) => {
script.setAttribute(
"data-status",
event.type === "load" ? "ready" : "error"
);
};
script.addEventListener("load", setAttributeFromEvent);
script.addEventListener("error", setAttributeFromEvent);
} else {
// Grab existing script status from attribute and set to state.
setStatus(script.getAttribute("data-status"));
}
// Event handler to update state status
const setStateFromEvent = (event) => {
setStatus(event.type === "load" ? "ready" : "error");
};
// Add event listeners
script.addEventListener("load", setStateFromEvent);
script.addEventListener("error", setStateFromEvent);
// Remove event listeners on cleanup
return () => {
if (script) {
script.removeEventListener("load", setStateFromEvent);
script.removeEventListener("error", setStateFromEvent);
}
};
},
[] // Run only once
);
return status;
}