-
-
Notifications
You must be signed in to change notification settings - Fork 22
/
Copy pathuseLoadGraphQL.mjs
90 lines (75 loc) · 2.68 KB
/
useLoadGraphQL.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
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
90
// @ts-check
/** @import { CacheKey } from "./Cache.mjs" */
import React from "react";
import fetchGraphQL from "./fetchGraphQL.mjs";
import LoadingCacheValue from "./LoadingCacheValue.mjs";
import useCache from "./useCache.mjs";
import useLoading from "./useLoading.mjs";
/**
* React hook to get a function for loading a GraphQL operation.
* @returns {LoadGraphQL} Loads a GraphQL operation.
*/
export default function useLoadGraphQL() {
const cache = useCache();
const loading = useLoading();
return React.useCallback(
(cacheKey, fetchUri, fetchOptions) => {
if (typeof cacheKey !== "string")
throw new TypeError("Argument 1 `cacheKey` must be a string.");
if (typeof fetchUri !== "string")
throw new TypeError("Argument 2 `fetchUri` must be a string.");
if (
typeof fetchOptions !== "object" ||
!fetchOptions ||
Array.isArray(fetchOptions)
)
throw new TypeError("Argument 3 `fetchOptions` must be an object.");
/** @type {RequestInit["signal"]} */
let signal;
/**
* Fetch options, modified without mutating the input.
* @type {RequestInit}
*/
let modifiedFetchOptions;
({ signal, ...modifiedFetchOptions } = fetchOptions);
const abortController = new AbortController();
// Respect an existing abort controller signal.
if (signal)
signal.aborted
? // Signal already aborted, so immediately abort.
abortController.abort()
: // Signal not already aborted, so setup a listener to abort when it
// does.
signal.addEventListener(
"abort",
() => {
abortController.abort();
},
{
// Prevent a memory leak if the existing abort controller is
// long lasting, or controls multiple things.
once: true,
},
);
modifiedFetchOptions.signal = abortController.signal;
return new LoadingCacheValue(
loading,
cache,
cacheKey,
fetchGraphQL(fetchUri, modifiedFetchOptions),
abortController,
);
},
[cache, loading],
);
}
/**
* Loads a GraphQL operation, using {@linkcode fetchGraphQL}.
* @callback LoadGraphQL
* @param {CacheKey} cacheKey Cache key to store the loading result under.
* @param {string} fetchUri [`fetch`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch)
* URI.
* @param {RequestInit} fetchOptions [`fetch`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch)
* options.
* @returns {LoadingCacheValue} The loading cache value.
*/