UNPKG

3.01 kBJavaScriptView Raw
1'use strict';
2
3const isObject = require('isobject/index.cjs.js');
4const { useCallback } = require('react');
5const createArgErrorMessageProd = require('../private/createArgErrorMessageProd');
6const LoadingCacheValue = require('./LoadingCacheValue');
7const fetchGraphQL = require('./fetchGraphQL');
8const useCache = require('./useCache');
9const useLoading = require('./useLoading');
10
11/**
12 * A React hook to get a function for loading a GraphQL operation.
13 * @kind function
14 * @name useLoadGraphQL
15 * @returns {LoadGraphQL} Loads a GraphQL operation.
16 * @example <caption>Ways to `import`.</caption>
17 * ```js
18 * import { useLoadGraphQL } from 'graphql-react';
19 * ```
20 *
21 * ```js
22 * import useLoadGraphQL from 'graphql-react/public/useLoadGraphQL.js';
23 * ```
24 * @example <caption>Ways to `require`.</caption>
25 * ```js
26 * const { useLoadGraphQL } = require('graphql-react');
27 * ```
28 *
29 * ```js
30 * const useLoadGraphQL = require('graphql-react/public/useLoadGraphQL');
31 * ```
32 */
33module.exports = function useLoadGraphQL() {
34 const cache = useCache();
35 const loading = useLoading();
36
37 return useCallback(
38 (cacheKey, fetchUri, fetchOptions) => {
39 if (typeof cacheKey !== 'string')
40 throw new TypeError(
41 typeof process === 'object' && process.env.NODE_ENV !== 'production'
42 ? 'Argument 1 `cacheKey` must be a string.'
43 : createArgErrorMessageProd(1)
44 );
45
46 if (typeof fetchUri !== 'string')
47 throw new TypeError(
48 typeof process === 'object' && process.env.NODE_ENV !== 'production'
49 ? 'Argument 2 `fetchUri` must be a string.'
50 : createArgErrorMessageProd(2)
51 );
52
53 if (!isObject(fetchOptions))
54 throw new TypeError(
55 typeof process === 'object' && process.env.NODE_ENV !== 'production'
56 ? 'Argument 3 `fetchOptions` must be an object.'
57 : createArgErrorMessageProd(3)
58 );
59
60 // Avoid mutating the input fetch options.
61 const { signal, ...modifiedFetchOptions } = fetchOptions;
62 const abortController = new AbortController();
63
64 // Respect an existing abort controller signal.
65 if (signal)
66 signal.aborted
67 ? // Signal already aborted, so immediately abort.
68 abortController.abort()
69 : // Signal not already aborted, so setup a listener to abort when it
70 // does.
71 signal.addEventListener(
72 'abort',
73 () => {
74 abortController.abort();
75 },
76 {
77 // Prevent a memory leak if the existing abort controller is
78 // long lasting, or controls multiple things.
79 once: true,
80 }
81 );
82
83 modifiedFetchOptions.signal = abortController.signal;
84
85 return new LoadingCacheValue(
86 loading,
87 cache,
88 cacheKey,
89 fetchGraphQL(fetchUri, modifiedFetchOptions),
90 abortController
91 );
92 },
93 [cache, loading]
94 );
95};