UNPKG

2.5 kBJavaScriptView Raw
1'use strict';
2
3const { useCallback, useEffect, useRef } = require('react');
4const createArgErrorMessageProd = require('../private/createArgErrorMessageProd');
5
6/**
7 * A React hook to create a memoized [loader]{@link Loader} from another, that
8 * automatically aborts previous loading that started via this hook when new
9 * loading starts via this hook, the hook arguments change, or the component
10 * unmounts.
11 * @kind function
12 * @name useAutoAbortLoad
13 * @param {Loader} load Memoized function that starts the loading.
14 * @returns {Loader} Memoized function that starts the loading.
15 * @example <caption>Ways to `import`.</caption>
16 * ```js
17 * import { useAutoAbortLoad } from 'graphql-react';
18 * ```
19 *
20 * ```js
21 * import useAutoAbortLoad from 'graphql-react/public/useAutoAbortLoad.js';
22 * ```
23 * @example <caption>Ways to `require`.</caption>
24 * ```js
25 * const { useAutoAbortLoad } = require('graphql-react');
26 * ```
27 *
28 * ```js
29 * const useAutoAbortLoad = require('graphql-react/public/useAutoAbortLoad');
30 * ```
31 */
32module.exports = function useAutoAbortLoad(load) {
33 if (typeof load !== 'function')
34 throw new TypeError(
35 typeof process === 'object' && process.env.NODE_ENV !== 'production'
36 ? 'Argument 1 `load` must be a function.'
37 : createArgErrorMessageProd(1)
38 );
39
40 const lastLoadingCacheValueRef = useRef();
41
42 useEffect(
43 () => () => {
44 if (lastLoadingCacheValueRef.current)
45 // Abort the last loading as it’s now redundant due to the changed
46 // dependencies. Checking if it’s already ended or aborted first is
47 // unnecessary.
48 lastLoadingCacheValueRef.current.abortController.abort();
49 },
50 [load]
51 );
52
53 return useCallback(() => {
54 if (lastLoadingCacheValueRef.current)
55 // Ensure the last loading is aborted before starting new loading.
56 // Checking if it’s already ended or aborted first is unnecessary.
57 lastLoadingCacheValueRef.current.abortController.abort();
58
59 const loadingCacheValue = load();
60
61 lastLoadingCacheValueRef.current = loadingCacheValue;
62
63 // After the loading cache value promise resolves, clear the ref (if it
64 // still holds the same loading cache value) to allow garbage collection.
65 // This might not be worth the bundle size increase.
66 loadingCacheValue.promise.then(() => {
67 if (lastLoadingCacheValueRef.current === loadingCacheValue)
68 lastLoadingCacheValueRef.current = null;
69 });
70
71 return loadingCacheValue;
72 }, [load]);
73};