-
-
Notifications
You must be signed in to change notification settings - Fork 22
/
Copy pathuseAutoAbortLoad.mjs
57 lines (47 loc) · 1.92 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
56
57
// @ts-check
/**
* @import LoadingCacheValue from "./LoadingCacheValue.mjs"
* @import { Loader } from "./types.mjs"
*/
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]);
}