-
-
Notifications
You must be signed in to change notification settings - Fork 170
/
Copy pathuse-unity-loader.ts
89 lines (86 loc) · 3.2 KB
/
use-unity-loader.ts
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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import { useEffect, useState } from "react";
import { isBrowserEnvironment } from "../constants/is-browser-environment";
import { UnityLoaderStatus } from "../enums/unity-loader-status";
import { UnityConfig } from "../exports";
/**
* Hook to embed a Unity Loader script.
* @param source The source of the unity loader.
* @returns a hook that returns the status of the loader.
*/
const useUnityLoader = (unityConfig: UnityConfig): UnityLoaderStatus => {
const [status, setStatus] = useState<UnityLoaderStatus>(
UnityLoaderStatus.Loading
);
// Effect hook will be invoked when the source changes.
useEffect(() => {
// It is possible for the application being rendered server side. In
// this scenario, the window is not available. We can't create a Unity
// Loader in this case.
if (isBrowserEnvironment === false) {
return undefined;
}
// If the script's source is null, we'll reset the status to idle.
if (unityConfig.loaderUrl === null) {
setStatus(UnityLoaderStatus.Idle);
return undefined;
}
/**
* Find existing script element by source. It may have been added by
* another instance of this hook.
*/
let script: HTMLScriptElement | null = window.document.querySelector(
`script[src="${unityConfig.loaderUrl}"]`
);
// If there wan't another instance of this script, we're going to create a
// new one with the provided source.
if (script === null) {
script = window.document.createElement("script");
script.type = "text/javascript";
script.src = unityConfig.loaderUrl;
script.async = true;
script.setAttribute("data-status", "loading");
// Add script to window.document body.
window.document.body.appendChild(script);
// Store status in attribute on script. This can be read by other
// instances of this hook.
script.addEventListener("load", () =>
script?.setAttribute("data-status", "loaded")
);
script.addEventListener("error", () =>
script?.setAttribute("data-status", "error")
);
} else {
// If there already was a script with the same source, grab its existing
// script status from attribute and set to state.
setStatus(
script.getAttribute("data-status") === "loaded"
? UnityLoaderStatus.Loaded
: UnityLoaderStatus.Error
);
}
/**
* Script event handler to update status in state. Even if the script
* already exists we still need to add event handlers to update the state
* for this hook instance.
* @param event The event that was triggered.
*/
const setStateFromEvent = (event: Event) =>
setStatus(
event.type === "load"
? UnityLoaderStatus.Loaded
: UnityLoaderStatus.Error
);
script.addEventListener("load", setStateFromEvent);
script.addEventListener("error", setStateFromEvent);
// Remove event listeners on cleanup.
return () => {
if (script !== null) {
script.removeEventListener("load", setStateFromEvent);
script.removeEventListener("error", setStateFromEvent);
script.remove();
}
};
}, [unityConfig.loaderUrl]);
return status;
};
export { useUnityLoader };