-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathuseAutoAbortLoad.mjs
55 lines (45 loc) · 1.94 KB
/
useAutoAbortLoad.mjs
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
// @ts-check
/** @typedef {import("./LoadingCacheValue.mjs").default} LoadingCacheValue */
/** @typedef {import("./types.mjs").Loader} Loader */
import React from "react";
/**
* React hook to create a memoized {@link Loader loader} from another, that
* automatically aborts previous loading that started via this hook when new
* loading starts via this hook, the hook arguments change, or the component
* unmounts.
* @param {Loader} load Memoized function that starts the loading.
* @returns {Loader} Memoized function that starts the loading.
*/
export default function useAutoAbortLoad(load) {
if (typeof load !== "function")
throw new TypeError("Argument 1 `load` must be a function.");
const lastLoadingCacheValueRef = React.useRef(
/** @type {LoadingCacheValue | undefined} */ (undefined)
);
React.useEffect(
() => () => {
if (lastLoadingCacheValueRef.current)
// Abort the last loading as it’s now redundant due to the changed
// dependencies. Checking if it’s already ended or aborted first is
// unnecessary.
lastLoadingCacheValueRef.current.abortController.abort();
},
[load]
);
return React.useCallback(() => {
if (lastLoadingCacheValueRef.current)
// Ensure the last loading is aborted before starting new loading.
// Checking if it’s already ended or aborted first is unnecessary.
lastLoadingCacheValueRef.current.abortController.abort();
const loadingCacheValue = load();
lastLoadingCacheValueRef.current = loadingCacheValue;
// After the loading cache value promise resolves, clear the ref (if it
// still holds the same loading cache value) to allow garbage collection.
// This might not be worth the bundle size increase.
loadingCacheValue.promise.then(() => {
if (lastLoadingCacheValueRef.current === loadingCacheValue)
lastLoadingCacheValueRef.current = undefined;
});
return loadingCacheValue;
}, [load]);
}