UNPKG

2.98 kBJavaScriptView Raw
1'use strict';
2
3const { useContext, useEffect, useRef } = require('react');
4const createArgErrorMessageProd = require('../private/createArgErrorMessageProd');
5const HYDRATION_TIME_MS = require('./HYDRATION_TIME_MS');
6const HydrationTimeStampContext = require('./HydrationTimeStampContext');
7const useCache = require('./useCache');
8
9/**
10 * A React hook to automatically load a [cache]{@link Cache#store} entry after
11 * the component mounts or the [cache context]{@link CacheContext} or any of the
12 * arguments change, except during the
13 * [hydration time]{@link HYDRATION_TIME_MS} if the
14 * [hydration time stamp context]{@link HydrationTimeStampContext} is populated
15 * and the [cache]{@link Cache#store} entry is already populated.
16 * @kind function
17 * @name useLoadOnMount
18 * @param {CacheKey} cacheKey Cache key.
19 * @param {Loader} load Memoized function that starts the loading.
20 * @example <caption>Ways to `import`.</caption>
21 * ```js
22 * import { useLoadOnMount } from 'graphql-react';
23 * ```
24 *
25 * ```js
26 * import useLoadOnMount from 'graphql-react/public/useLoadOnMount.js';
27 * ```
28 * @example <caption>Ways to `require`.</caption>
29 * ```js
30 * const { useLoadOnMount } = require('graphql-react');
31 * ```
32 *
33 * ```js
34 * const useLoadOnMount = require('graphql-react/public/useLoadOnMount');
35 * ```
36 */
37module.exports = function useLoadOnMount(cacheKey, load) {
38 if (typeof cacheKey !== 'string')
39 throw new TypeError(
40 typeof process === 'object' && process.env.NODE_ENV !== 'production'
41 ? 'Argument 1 `cacheKey` must be a string.'
42 : createArgErrorMessageProd(1)
43 );
44
45 if (typeof load !== 'function')
46 throw new TypeError(
47 typeof process === 'object' && process.env.NODE_ENV !== 'production'
48 ? 'Argument 2 `load` must be a function.'
49 : createArgErrorMessageProd(2)
50 );
51
52 const cache = useCache();
53 const hydrationTimeStamp = useContext(HydrationTimeStampContext);
54
55 if (
56 // Allowed to be undefined for apps that don’t provide this context.
57 hydrationTimeStamp !== undefined &&
58 typeof hydrationTimeStamp !== 'number'
59 )
60 throw new TypeError('Hydration time stamp context value must be a number.');
61
62 const startedRef = useRef();
63
64 useEffect(() => {
65 if (
66 // Loading the same as currently specified wasn’t already started.
67 !(
68 startedRef.current &&
69 startedRef.current.cache === cache &&
70 startedRef.current.cacheKey === cacheKey &&
71 startedRef.current.load === load
72 ) &&
73 // Waterfall loaded cache isn’t being hydrated.
74 !(
75 cacheKey in cache.store &&
76 // Within the hydration time. If `hydrationTimeStamp` is undefined the
77 // comparison safely evaluates to false.
78 performance.now() - hydrationTimeStamp < HYDRATION_TIME_MS
79 )
80 ) {
81 startedRef.current = {
82 cache,
83 cacheKey,
84 load,
85 };
86
87 load();
88 }
89 }, [cache, cacheKey, hydrationTimeStamp, load]);
90};