@khanacademy/wonder-blocks-data 10.0.5 → 10.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +38 -0
- package/dist/components/data.d.ts +52 -0
- package/dist/components/data.js.flow +63 -0
- package/dist/components/gql-router.d.ts +24 -0
- package/dist/components/gql-router.js.flow +33 -0
- package/dist/components/intercept-context.d.ts +10 -0
- package/dist/components/intercept-context.js.flow +19 -0
- package/dist/components/intercept-requests.d.ts +42 -0
- package/dist/components/intercept-requests.js.flow +51 -0
- package/dist/components/track-data.d.ts +11 -0
- package/dist/components/track-data.js.flow +18 -0
- package/dist/es/index.js +196 -214
- package/dist/hooks/use-cached-effect.d.ts +70 -0
- package/dist/hooks/use-cached-effect.js.flow +85 -0
- package/dist/hooks/use-gql-router-context.d.ts +5 -0
- package/dist/hooks/use-gql-router-context.js.flow +15 -0
- package/dist/hooks/use-gql.d.ts +12 -0
- package/dist/hooks/use-gql.js.flow +29 -0
- package/dist/hooks/use-hydratable-effect.d.ts +102 -0
- package/dist/hooks/use-hydratable-effect.js.flow +125 -0
- package/dist/hooks/use-request-interception.d.ts +14 -0
- package/dist/hooks/use-request-interception.js.flow +25 -0
- package/dist/hooks/use-server-effect.d.ts +39 -0
- package/dist/hooks/use-server-effect.js.flow +51 -0
- package/dist/hooks/use-shared-cache.d.ts +32 -0
- package/dist/hooks/use-shared-cache.js.flow +43 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +198 -219
- package/dist/index.js.flow +48 -2
- package/dist/util/data-error.d.ts +45 -0
- package/dist/util/data-error.js.flow +64 -0
- package/dist/util/get-gql-data-from-response.d.ts +4 -0
- package/dist/util/get-gql-data-from-response.js.flow +13 -0
- package/dist/util/get-gql-request-id.d.ts +5 -0
- package/dist/util/get-gql-request-id.js.flow +20 -0
- package/dist/util/gql-error.d.ts +28 -0
- package/dist/util/gql-error.js.flow +43 -0
- package/dist/util/gql-router-context.d.ts +3 -0
- package/dist/util/gql-router-context.js.flow +10 -0
- package/dist/util/gql-types.d.ts +34 -0
- package/dist/util/gql-types.js.flow +53 -0
- package/dist/util/graphql-document-node-parser.d.ts +18 -0
- package/dist/util/graphql-document-node-parser.js.flow +31 -0
- package/dist/util/graphql-types.d.ts +19 -0
- package/dist/util/graphql-types.js.flow +30 -0
- package/dist/util/hydration-cache-api.d.ts +17 -0
- package/dist/util/hydration-cache-api.js.flow +30 -0
- package/dist/util/merge-gql-context.d.ts +8 -0
- package/dist/util/merge-gql-context.js.flow +19 -0
- package/dist/util/purge-caches.d.ts +8 -0
- package/dist/util/purge-caches.js.flow +15 -0
- package/dist/util/request-api.d.ts +28 -0
- package/dist/util/request-api.js.flow +34 -0
- package/dist/util/request-fulfillment.d.ts +37 -0
- package/dist/util/request-fulfillment.js.flow +50 -0
- package/dist/util/request-tracking.d.ts +62 -0
- package/dist/util/request-tracking.js.flow +81 -0
- package/dist/util/result-from-cache-response.d.ts +5 -0
- package/dist/util/result-from-cache-response.js.flow +15 -0
- package/dist/util/scoped-in-memory-cache.d.ts +38 -0
- package/dist/util/scoped-in-memory-cache.js.flow +57 -0
- package/dist/util/serializable-in-memory-cache.d.ts +16 -0
- package/dist/util/serializable-in-memory-cache.js.flow +26 -0
- package/dist/util/ssr-cache.d.ts +51 -0
- package/dist/util/ssr-cache.js.flow +87 -0
- package/dist/util/status.d.ts +10 -0
- package/dist/util/status.js.flow +19 -0
- package/dist/util/to-gql-operation.d.ts +32 -0
- package/dist/util/to-gql-operation.js.flow +45 -0
- package/dist/util/types.d.ts +111 -0
- package/dist/util/types.js.flow +151 -0
- package/package.json +5 -6
- package/src/components/__tests__/{data.test.js → data.test.tsx} +50 -16
- package/src/components/__tests__/{gql-router.test.js → gql-router.test.tsx} +6 -7
- package/src/components/__tests__/{intercept-requests.test.js → intercept-requests.test.tsx} +4 -5
- package/src/components/__tests__/{track-data.test.js → track-data.test.tsx} +4 -5
- package/src/components/{data.js → data.ts} +13 -21
- package/src/components/{gql-router.js → gql-router.tsx} +14 -16
- package/src/components/{intercept-context.js → intercept-context.ts} +5 -4
- package/src/components/{intercept-requests.js → intercept-requests.tsx} +9 -10
- package/src/components/{track-data.js → track-data.tsx} +5 -6
- package/src/hooks/__tests__/{use-cached-effect.test.js → use-cached-effect.test.tsx} +65 -63
- package/src/hooks/__tests__/{use-gql-router-context.test.js → use-gql-router-context.test.tsx} +9 -9
- package/src/hooks/__tests__/{use-gql.test.js → use-gql.test.tsx} +23 -24
- package/src/hooks/__tests__/{use-hydratable-effect.test.js → use-hydratable-effect.test.ts} +52 -54
- package/src/hooks/__tests__/{use-request-interception.test.js → use-request-interception.test.tsx} +7 -5
- package/src/hooks/__tests__/{use-server-effect.test.js → use-server-effect.test.ts} +16 -10
- package/src/hooks/__tests__/{use-shared-cache.test.js → use-shared-cache.test.ts} +13 -13
- package/src/hooks/{use-cached-effect.js → use-cached-effect.ts} +34 -31
- package/src/hooks/{use-gql-router-context.js → use-gql-router-context.ts} +6 -7
- package/src/hooks/{use-gql.js → use-gql.ts} +9 -9
- package/src/hooks/{use-hydratable-effect.js → use-hydratable-effect.ts} +60 -67
- package/src/hooks/{use-request-interception.js → use-request-interception.ts} +6 -6
- package/src/hooks/{use-server-effect.js → use-server-effect.ts} +12 -14
- package/src/hooks/{use-shared-cache.js → use-shared-cache.ts} +16 -11
- package/src/index.ts +46 -0
- package/src/util/__tests__/{get-gql-data-from-response.test.js → get-gql-data-from-response.test.ts} +1 -2
- package/src/util/__tests__/{get-gql-request-id.test.js → get-gql-request-id.test.ts} +10 -12
- package/src/util/__tests__/{graphql-document-node-parser.test.js → graphql-document-node-parser.test.ts} +12 -13
- package/src/util/__tests__/{hydration-cache-api.test.js → hydration-cache-api.test.ts} +3 -4
- package/src/util/__tests__/{merge-gql-context.test.js → merge-gql-context.test.ts} +5 -6
- package/src/util/__tests__/{purge-caches.test.js → purge-caches.test.ts} +3 -4
- package/src/util/__tests__/{request-api.test.js → request-api.test.ts} +5 -5
- package/src/util/__tests__/{request-fulfillment.test.js → request-fulfillment.test.ts} +2 -3
- package/src/util/__tests__/{request-tracking.test.js → request-tracking.test.tsx} +15 -8
- package/src/util/__tests__/{result-from-cache-response.test.js → result-from-cache-response.test.ts} +3 -5
- package/src/util/__tests__/{scoped-in-memory-cache.test.js → scoped-in-memory-cache.test.ts} +5 -6
- package/src/util/__tests__/{serializable-in-memory-cache.test.js → serializable-in-memory-cache.test.ts} +8 -8
- package/src/util/__tests__/{ssr-cache.test.js → ssr-cache.test.ts} +5 -4
- package/src/util/__tests__/{to-gql-operation.test.js → to-gql-operation.test.ts} +5 -4
- package/src/util/{data-error.js → data-error.ts} +3 -4
- package/src/util/{get-gql-data-from-response.js → get-gql-data-from-response.ts} +3 -8
- package/src/util/{get-gql-request-id.js → get-gql-request-id.ts} +13 -17
- package/src/util/{gql-error.js → gql-error.ts} +3 -4
- package/src/util/gql-router-context.ts +6 -0
- package/src/util/{gql-types.js → gql-types.ts} +27 -23
- package/src/util/{graphql-document-node-parser.js → graphql-document-node-parser.ts} +8 -9
- package/src/util/graphql-types.ts +27 -0
- package/src/util/{hydration-cache-api.js → hydration-cache-api.ts} +6 -4
- package/src/util/{merge-gql-context.js → merge-gql-context.ts} +3 -3
- package/src/util/{purge-caches.js → purge-caches.ts} +2 -3
- package/src/util/{request-api.js → request-api.ts} +4 -5
- package/src/util/{request-fulfillment.js → request-fulfillment.ts} +15 -14
- package/src/util/{request-tracking.js → request-tracking.ts} +15 -16
- package/src/util/{result-from-cache-response.js → result-from-cache-response.ts} +6 -7
- package/src/util/{scoped-in-memory-cache.js → scoped-in-memory-cache.ts} +3 -4
- package/src/util/{serializable-in-memory-cache.js → serializable-in-memory-cache.ts} +5 -6
- package/src/util/{ssr-cache.js → ssr-cache.ts} +21 -20
- package/src/util/{status.js → status.ts} +5 -6
- package/src/util/{to-gql-operation.js → to-gql-operation.ts} +4 -5
- package/src/util/{types.js → types.ts} +41 -49
- package/tsconfig.json +11 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/src/__docs__/_overview_.stories.mdx +0 -18
- package/src/__docs__/_overview_graphql.stories.mdx +0 -35
- package/src/__docs__/_overview_ssr_.stories.mdx +0 -185
- package/src/__docs__/_overview_testing_.stories.mdx +0 -123
- package/src/__docs__/exports.abort-inflight-requests.stories.mdx +0 -20
- package/src/__docs__/exports.data-error.stories.mdx +0 -23
- package/src/__docs__/exports.data-errors.stories.mdx +0 -23
- package/src/__docs__/exports.data.stories.mdx +0 -146
- package/src/__docs__/exports.fetch-tracked-requests.stories.mdx +0 -24
- package/src/__docs__/exports.get-gql-request-id.stories.mdx +0 -24
- package/src/__docs__/exports.gql-error.stories.mdx +0 -23
- package/src/__docs__/exports.gql-errors.stories.mdx +0 -20
- package/src/__docs__/exports.gql-router.stories.mdx +0 -29
- package/src/__docs__/exports.has-tracked-requests-to-be-fetched.stories.mdx +0 -20
- package/src/__docs__/exports.intercept-requests.stories.mdx +0 -69
- package/src/__docs__/exports.intialize-hydration-cache.stories.mdx +0 -29
- package/src/__docs__/exports.purge-caches.stories.mdx +0 -23
- package/src/__docs__/exports.purge-hydration-cache.stories.mdx +0 -24
- package/src/__docs__/exports.scoped-in-memory-cache.stories.mdx +0 -92
- package/src/__docs__/exports.serializable-in-memory-cache.stories.mdx +0 -112
- package/src/__docs__/exports.shared-cache.stories.mdx +0 -16
- package/src/__docs__/exports.status.stories.mdx +0 -31
- package/src/__docs__/exports.track-data.stories.mdx +0 -209
- package/src/__docs__/exports.use-cached-effect.stories.mdx +0 -44
- package/src/__docs__/exports.use-gql.stories.mdx +0 -41
- package/src/__docs__/exports.use-hydratable-effect.stories.mdx +0 -43
- package/src/__docs__/exports.use-server-effect.stories.mdx +0 -50
- package/src/__docs__/exports.use-shared-cache.stories.mdx +0 -30
- package/src/__docs__/exports.when-client-side.stories.mdx +0 -33
- package/src/__docs__/types.cached-response.stories.mdx +0 -29
- package/src/__docs__/types.error-options.stories.mdx +0 -21
- package/src/__docs__/types.fetch-policy.stories.mdx +0 -44
- package/src/__docs__/types.gql-context.stories.mdx +0 -20
- package/src/__docs__/types.gql-fetch-fn.stories.mdx +0 -24
- package/src/__docs__/types.gql-fetch-options.stories.mdx +0 -24
- package/src/__docs__/types.gql-operation-type.stories.mdx +0 -24
- package/src/__docs__/types.gql-operation.stories.mdx +0 -67
- package/src/__docs__/types.raw-scoped-cache.stories.mdx +0 -27
- package/src/__docs__/types.response-cache.stories.mdx +0 -33
- package/src/__docs__/types.result.stories.mdx +0 -39
- package/src/__docs__/types.scoped-cache.stories.mdx +0 -114
- package/src/__docs__/types.valid-cache-data.stories.mdx +0 -23
- package/src/index.js +0 -55
- package/src/util/gql-router-context.js +0 -6
- package/src/util/graphql-types.js +0 -30
- /package/src/hooks/__tests__/__snapshots__/{use-shared-cache.test.js.snap → use-shared-cache.test.ts.snap} +0 -0
- /package/src/util/__tests__/__snapshots__/{scoped-in-memory-cache.test.js.snap → scoped-in-memory-cache.test.ts.snap} +0 -0
- /package/src/util/__tests__/__snapshots__/{serializable-in-memory-cache.test.js.snap → serializable-in-memory-cache.test.ts.snap} +0 -0
|
@@ -1,31 +1,25 @@
|
|
|
1
|
-
// @flow
|
|
2
1
|
import * as React from "react";
|
|
3
2
|
import {useForceUpdate} from "@khanacademy/wonder-blocks-core";
|
|
4
|
-
import {DataError, DataErrors} from "../util/data-error
|
|
3
|
+
import {DataError, DataErrors} from "../util/data-error";
|
|
5
4
|
|
|
6
|
-
import {RequestFulfillment} from "../util/request-fulfillment
|
|
7
|
-
import {Status} from "../util/status
|
|
5
|
+
import {RequestFulfillment} from "../util/request-fulfillment";
|
|
6
|
+
import {Status} from "../util/status";
|
|
8
7
|
|
|
9
|
-
import {useSharedCache} from "./use-shared-cache
|
|
10
|
-
import {useRequestInterception} from "./use-request-interception
|
|
8
|
+
import {useSharedCache} from "./use-shared-cache";
|
|
9
|
+
import {useRequestInterception} from "./use-request-interception";
|
|
11
10
|
|
|
12
|
-
import type {Result, ValidCacheData} from "../util/types
|
|
11
|
+
import type {Result, ValidCacheData} from "../util/types";
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
// have fixed:
|
|
16
|
-
// https://github.com/import-js/eslint-plugin-import/issues/2073
|
|
17
|
-
// eslint-disable-next-line import/named
|
|
18
|
-
import {FetchPolicy} from "../util/types.js";
|
|
13
|
+
import {FetchPolicy} from "../util/types";
|
|
19
14
|
|
|
20
|
-
type CachedEffectOptions<TData
|
|
15
|
+
type CachedEffectOptions<TData extends ValidCacheData> = {
|
|
21
16
|
/**
|
|
22
17
|
* The policy to use when determining how to retrieve the request data from
|
|
23
18
|
* cache and network.
|
|
24
19
|
*
|
|
25
20
|
* Defaults to `FetchPolicy.CacheBeforeNetwork`.
|
|
26
21
|
*/
|
|
27
|
-
fetchPolicy?: FetchPolicy
|
|
28
|
-
|
|
22
|
+
fetchPolicy?: typeof FetchPolicy[keyof typeof FetchPolicy];
|
|
29
23
|
/**
|
|
30
24
|
* When `true`, the effect will not be executed; otherwise, the effect will
|
|
31
25
|
* be executed.
|
|
@@ -35,8 +29,7 @@ type CachedEffectOptions<TData: ValidCacheData> = {|
|
|
|
35
29
|
*
|
|
36
30
|
* Default is `false`.
|
|
37
31
|
*/
|
|
38
|
-
skip?: boolean
|
|
39
|
-
|
|
32
|
+
skip?: boolean;
|
|
40
33
|
/**
|
|
41
34
|
* When `true`, the effect will not reset the result to the loading status
|
|
42
35
|
* while executing if the requestId changes, instead, returning
|
|
@@ -47,8 +40,7 @@ type CachedEffectOptions<TData: ValidCacheData> = {|
|
|
|
47
40
|
* loading; old pending effects are discarded on changes and as such this
|
|
48
41
|
* value has no effect in that case.
|
|
49
42
|
*/
|
|
50
|
-
retainResultOnChange?: boolean
|
|
51
|
-
|
|
43
|
+
retainResultOnChange?: boolean;
|
|
52
44
|
/**
|
|
53
45
|
* Callback that is invoked if the result for the given hook has changed.
|
|
54
46
|
*
|
|
@@ -59,8 +51,7 @@ type CachedEffectOptions<TData: ValidCacheData> = {|
|
|
|
59
51
|
* When not defined, the hook will ensure the component re-renders to pick
|
|
60
52
|
* up the latest result.
|
|
61
53
|
*/
|
|
62
|
-
onResultChanged?: (result: Result<TData>) => void
|
|
63
|
-
|
|
54
|
+
onResultChanged?: (result: Result<TData>) => void;
|
|
64
55
|
/**
|
|
65
56
|
* Scope to use with the shared cache.
|
|
66
57
|
*
|
|
@@ -69,8 +60,8 @@ type CachedEffectOptions<TData: ValidCacheData> = {|
|
|
|
69
60
|
*
|
|
70
61
|
* Changing this value after the first call is not supported.
|
|
71
62
|
*/
|
|
72
|
-
scope?: string
|
|
73
|
-
|
|
63
|
+
scope?: string;
|
|
64
|
+
};
|
|
74
65
|
|
|
75
66
|
const DefaultScope = "useCachedEffect";
|
|
76
67
|
|
|
@@ -90,12 +81,12 @@ const DefaultScope = "useCachedEffect";
|
|
|
90
81
|
* Once the request has been tried once and a non-loading response has been
|
|
91
82
|
* cached, the request will not executed made again.
|
|
92
83
|
*/
|
|
93
|
-
export const useCachedEffect = <TData
|
|
84
|
+
export const useCachedEffect = <TData extends ValidCacheData>(
|
|
94
85
|
requestId: string,
|
|
95
86
|
handler: () => Promise<TData>,
|
|
96
|
-
options: CachedEffectOptions<TData> =
|
|
97
|
-
CachedEffectOptions<TData
|
|
98
|
-
|
|
87
|
+
options: CachedEffectOptions<TData> = {} as Partial<
|
|
88
|
+
CachedEffectOptions<TData>
|
|
89
|
+
>,
|
|
99
90
|
): [Result<TData>, () => void] => {
|
|
100
91
|
const {
|
|
101
92
|
fetchPolicy = FetchPolicy.CacheBeforeNetwork,
|
|
@@ -112,13 +103,13 @@ export const useCachedEffect = <TData: ValidCacheData>(
|
|
|
112
103
|
// Instead of using state, which would be local to just this hook instance,
|
|
113
104
|
// we use a shared in-memory cache.
|
|
114
105
|
const [mostRecentResult, setMostRecentResult] = useSharedCache<
|
|
115
|
-
Result<TData
|
|
116
|
-
>(
|
|
117
|
-
requestId, // The
|
|
118
|
-
scope, // The scope of the cached items
|
|
106
|
+
Result<TData>
|
|
107
|
+
>( // The key of the cached item
|
|
108
|
+
requestId, // The scope of the cached items
|
|
119
109
|
// No default value. We don't want the loading status there; to ensure
|
|
120
110
|
// that all calls when the request is in-flight will update once that
|
|
121
111
|
// request is done, we want the cache to be empty until that point.
|
|
112
|
+
scope,
|
|
122
113
|
);
|
|
123
114
|
const forceUpdate = useForceUpdate();
|
|
124
115
|
// For the NetworkOnly fetch policy, we ignore the cached value.
|
|
@@ -131,8 +122,11 @@ export const useCachedEffect = <TData: ValidCacheData>(
|
|
|
131
122
|
// We aren't using useCallback here because we need to make sure that
|
|
132
123
|
// if we are rememo-izing, we cancel any inflight request for the old
|
|
133
124
|
// callback.
|
|
125
|
+
// @ts-expect-error [FEI-5019] - TS2339 - Property 'cancel' does not exist on type 'never'.
|
|
134
126
|
currentRequestRef.current?.cancel();
|
|
127
|
+
// @ts-expect-error [FEI-5019] - TS2322 - Type 'null' is not assignable to type 'undefined'.
|
|
135
128
|
currentRequestRef.current = null;
|
|
129
|
+
// @ts-expect-error [FEI-5019] - TS2322 - Type 'null' is not assignable to type 'undefined'.
|
|
136
130
|
networkResultRef.current = null;
|
|
137
131
|
|
|
138
132
|
const fetchFn = () => {
|
|
@@ -159,6 +153,7 @@ export const useCachedEffect = <TData: ValidCacheData>(
|
|
|
159
153
|
},
|
|
160
154
|
);
|
|
161
155
|
|
|
156
|
+
// @ts-expect-error [FEI-5019] - TS2339 - Property 'request' does not exist on type 'never'.
|
|
162
157
|
if (request === currentRequestRef.current?.request) {
|
|
163
158
|
// The request inflight is the same, so do nothing.
|
|
164
159
|
// NOTE: Perhaps if invoked via a refetch, we will want to
|
|
@@ -167,9 +162,11 @@ export const useCachedEffect = <TData: ValidCacheData>(
|
|
|
167
162
|
}
|
|
168
163
|
|
|
169
164
|
// Clear the last network result.
|
|
165
|
+
// @ts-expect-error [FEI-5019] - TS2322 - Type 'null' is not assignable to type 'undefined'.
|
|
170
166
|
networkResultRef.current = null;
|
|
171
167
|
|
|
172
168
|
// Cancel the previous request.
|
|
169
|
+
// @ts-expect-error [FEI-5019] - TS2339 - Property 'cancel' does not exist on type 'never'.
|
|
173
170
|
currentRequestRef.current?.cancel();
|
|
174
171
|
|
|
175
172
|
// TODO(somewhatabstract, FEI-4276):
|
|
@@ -181,6 +178,7 @@ export const useCachedEffect = <TData: ValidCacheData>(
|
|
|
181
178
|
// Catching shouldn't serve a purpose.
|
|
182
179
|
// eslint-disable-next-line promise/catch-or-return
|
|
183
180
|
request.then((result) => {
|
|
181
|
+
// @ts-expect-error [FEI-5019] - TS2322 - Type 'null' is not assignable to type 'undefined'.
|
|
184
182
|
currentRequestRef.current = null;
|
|
185
183
|
if (cancel) {
|
|
186
184
|
// We don't modify our result if the request was cancelled
|
|
@@ -191,6 +189,7 @@ export const useCachedEffect = <TData: ValidCacheData>(
|
|
|
191
189
|
|
|
192
190
|
// Now we need to update the cache and notify or force a rerender.
|
|
193
191
|
setMostRecentResult(result);
|
|
192
|
+
// @ts-expect-error [FEI-5019] - TS2322 - Type 'Result<TData>' is not assignable to type 'undefined'.
|
|
194
193
|
networkResultRef.current = result;
|
|
195
194
|
|
|
196
195
|
if (onResultChanged != null) {
|
|
@@ -205,6 +204,7 @@ export const useCachedEffect = <TData: ValidCacheData>(
|
|
|
205
204
|
return; // Shut up eslint always-return rule.
|
|
206
205
|
});
|
|
207
206
|
|
|
207
|
+
// @ts-expect-error [FEI-5019] - TS2322 - Type '{ requestId: string; request: Promise<Result<TData>>; cancel(): void; }' is not assignable to type 'undefined'.
|
|
208
208
|
currentRequestRef.current = {
|
|
209
209
|
requestId,
|
|
210
210
|
request,
|
|
@@ -265,7 +265,9 @@ export const useCachedEffect = <TData: ValidCacheData>(
|
|
|
265
265
|
}
|
|
266
266
|
fetchRequest();
|
|
267
267
|
return () => {
|
|
268
|
+
// @ts-expect-error [FEI-5019] - TS2339 - Property 'cancel' does not exist on type 'never'.
|
|
268
269
|
currentRequestRef.current?.cancel();
|
|
270
|
+
// @ts-expect-error [FEI-5019] - TS2322 - Type 'null' is not assignable to type 'undefined'.
|
|
269
271
|
currentRequestRef.current = null;
|
|
270
272
|
};
|
|
271
273
|
}, [shouldFetch, fetchRequest]);
|
|
@@ -286,5 +288,6 @@ export const useCachedEffect = <TData: ValidCacheData>(
|
|
|
286
288
|
lastResultAgnosticOfIdRef.current = result;
|
|
287
289
|
|
|
288
290
|
// We return the result and a function for triggering a refetch.
|
|
291
|
+
// @ts-expect-error [FEI-5019] - TS2322 - Type '{ status: "loading"; } | { status: "error"; error: Error; } | { status: "aborted"; } | { status: "success"; data: ValidCacheData; }' is not assignable to type 'Result<TData>'.
|
|
289
292
|
return [result, fetchRequest];
|
|
290
293
|
};
|
|
@@ -1,17 +1,16 @@
|
|
|
1
|
-
// @flow
|
|
2
1
|
import {useContext, useRef, useMemo} from "react";
|
|
3
2
|
|
|
4
|
-
import {mergeGqlContext} from "../util/merge-gql-context
|
|
5
|
-
import {GqlRouterContext} from "../util/gql-router-context
|
|
6
|
-
import {GqlError, GqlErrors} from "../util/gql-error
|
|
3
|
+
import {mergeGqlContext} from "../util/merge-gql-context";
|
|
4
|
+
import {GqlRouterContext} from "../util/gql-router-context";
|
|
5
|
+
import {GqlError, GqlErrors} from "../util/gql-error";
|
|
7
6
|
|
|
8
|
-
import type {GqlRouterConfiguration, GqlContext} from "../util/gql-types
|
|
7
|
+
import type {GqlRouterConfiguration, GqlContext} from "../util/gql-types";
|
|
9
8
|
|
|
10
9
|
/**
|
|
11
10
|
* Construct a GqlRouterContext from the current one and partial context.
|
|
12
11
|
*/
|
|
13
|
-
export const useGqlRouterContext = <TContext
|
|
14
|
-
contextOverrides: Partial<TContext> =
|
|
12
|
+
export const useGqlRouterContext = <TContext extends GqlContext>(
|
|
13
|
+
contextOverrides: Partial<TContext> = {} as Partial<TContext>,
|
|
15
14
|
): GqlRouterConfiguration<TContext> => {
|
|
16
15
|
// This hook only works if the `GqlRouter` has been used to setup context.
|
|
17
16
|
const gqlRouterContext = useContext(GqlRouterContext);
|
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
// @flow
|
|
2
1
|
import {useCallback} from "react";
|
|
3
2
|
|
|
4
|
-
import {mergeGqlContext} from "../util/merge-gql-context
|
|
5
|
-
import {useGqlRouterContext} from "./use-gql-router-context
|
|
6
|
-
import {getGqlDataFromResponse} from "../util/get-gql-data-from-response
|
|
3
|
+
import {mergeGqlContext} from "../util/merge-gql-context";
|
|
4
|
+
import {useGqlRouterContext} from "./use-gql-router-context";
|
|
5
|
+
import {getGqlDataFromResponse} from "../util/get-gql-data-from-response";
|
|
7
6
|
|
|
8
7
|
import type {
|
|
9
8
|
GqlContext,
|
|
10
9
|
GqlOperation,
|
|
11
10
|
GqlFetchOptions,
|
|
12
|
-
} from "../util/gql-types
|
|
11
|
+
} from "../util/gql-types";
|
|
13
12
|
|
|
14
13
|
/**
|
|
15
14
|
* Hook to obtain a gqlFetch function for performing GraphQL requests.
|
|
@@ -21,9 +20,9 @@ import type {
|
|
|
21
20
|
* Values in the partial context given to the returned fetch function will
|
|
22
21
|
* only be included if they have a value other than undefined.
|
|
23
22
|
*/
|
|
24
|
-
export const useGql = <TContext
|
|
25
|
-
context: Partial<TContext> =
|
|
26
|
-
): (<TData, TVariables
|
|
23
|
+
export const useGql = <TContext extends GqlContext>(
|
|
24
|
+
context: Partial<TContext> = {} as Partial<TContext>,
|
|
25
|
+
): (<TData, TVariables extends Record<any, any>>(
|
|
27
26
|
operation: GqlOperation<TData, TVariables>,
|
|
28
27
|
options?: GqlFetchOptions<TVariables, TContext>,
|
|
29
28
|
) => Promise<TData>) => {
|
|
@@ -36,7 +35,7 @@ export const useGql = <TContext: GqlContext>(
|
|
|
36
35
|
// making a new one. That then means they can safely use the return value
|
|
37
36
|
// in hooks deps without fear of it triggering extra renders.
|
|
38
37
|
const gqlFetch = useCallback(
|
|
39
|
-
<TData, TVariables
|
|
38
|
+
<TData, TVariables extends Record<any, any>>(
|
|
40
39
|
operation: GqlOperation<TData, TVariables>,
|
|
41
40
|
options: GqlFetchOptions<TVariables, TContext> = Object.freeze({}),
|
|
42
41
|
) => {
|
|
@@ -51,5 +50,6 @@ export const useGql = <TContext: GqlContext>(
|
|
|
51
50
|
},
|
|
52
51
|
[gqlRouterContext],
|
|
53
52
|
);
|
|
53
|
+
// @ts-expect-error [FEI-5019] - TS2322 - Type '<TData, TVariables extends Record<any, any>>(operation: GqlOperation<TData, TVariables>, options?: GqlFetchOptions<TVariables, TContext>) => Promise<unknown>' is not assignable to type '<TData, TVariables extends Record<any, any>>(operation: GqlOperation<TData, TVariables>, options?: GqlFetchOptions<TVariables, TContext> | undefined) => Promise<...>'.
|
|
54
54
|
return gqlFetch;
|
|
55
55
|
};
|
|
@@ -1,21 +1,17 @@
|
|
|
1
|
-
// @flow
|
|
2
1
|
import * as React from "react";
|
|
3
2
|
|
|
4
|
-
import {useServerEffect} from "./use-server-effect
|
|
5
|
-
import {useSharedCache} from "./use-shared-cache
|
|
6
|
-
import {useCachedEffect} from "./use-cached-effect
|
|
3
|
+
import {useServerEffect} from "./use-server-effect";
|
|
4
|
+
import {useSharedCache} from "./use-shared-cache";
|
|
5
|
+
import {useCachedEffect} from "./use-cached-effect";
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
// https://github.com/import-js/eslint-plugin-import/issues/2073
|
|
11
|
-
// eslint-disable-next-line import/named
|
|
12
|
-
import {FetchPolicy} from "../util/types.js";
|
|
13
|
-
import type {Result, ValidCacheData} from "../util/types.js";
|
|
7
|
+
import {FetchPolicy} from "../util/types";
|
|
8
|
+
import type {Result, ValidCacheData} from "../util/types";
|
|
14
9
|
|
|
15
10
|
/**
|
|
16
11
|
* Policies to define how a hydratable effect should behave client-side.
|
|
17
12
|
*/
|
|
18
|
-
|
|
13
|
+
// TODO(FEI-5000): Convert to TS enum after all codebases have been migrated
|
|
14
|
+
export const WhenClientSide = {
|
|
19
15
|
/**
|
|
20
16
|
* The result from executing the effect server-side will not be hydrated.
|
|
21
17
|
* The effect will always be executed client-side.
|
|
@@ -24,7 +20,7 @@ export enum WhenClientSide {
|
|
|
24
20
|
* for properly hydrating this component (for example, the action invokes
|
|
25
21
|
* Apollo which manages its own cache to ensure things render properly).
|
|
26
22
|
*/
|
|
27
|
-
DoNotHydrate,
|
|
23
|
+
DoNotHydrate: "DoNotHydrate" as const,
|
|
28
24
|
|
|
29
25
|
/**
|
|
30
26
|
* The result from executing the effect server-side will be hydrated.
|
|
@@ -32,7 +28,7 @@ export enum WhenClientSide {
|
|
|
32
28
|
* be hydrated (i.e. both error and success hydration results prevent the
|
|
33
29
|
* effect running client-side).
|
|
34
30
|
*/
|
|
35
|
-
ExecuteWhenNoResult,
|
|
31
|
+
ExecuteWhenNoResult: "ExecuteWhenNoResult" as const,
|
|
36
32
|
|
|
37
33
|
/**
|
|
38
34
|
* The result from executing the effect server-side will be hydrated.
|
|
@@ -41,17 +37,17 @@ export enum WhenClientSide {
|
|
|
41
37
|
* If the hydrated result was not a success result, or there was no
|
|
42
38
|
* hydrated result, the effect will not be executed.
|
|
43
39
|
*/
|
|
44
|
-
ExecuteWhenNoSuccessResult,
|
|
40
|
+
ExecuteWhenNoSuccessResult: "ExecuteWhenNoSuccessResult" as const,
|
|
45
41
|
|
|
46
42
|
/**
|
|
47
43
|
* The result from executing the effect server-side will be hydrated.
|
|
48
44
|
* The effect will always be executed client-side, regardless of the
|
|
49
45
|
* hydrated result status.
|
|
50
46
|
*/
|
|
51
|
-
AlwaysExecute,
|
|
52
|
-
}
|
|
47
|
+
AlwaysExecute: "AlwaysExecute" as const,
|
|
48
|
+
} as const;
|
|
53
49
|
|
|
54
|
-
type HydratableEffectOptions<TData
|
|
50
|
+
type HydratableEffectOptions<TData extends ValidCacheData> = {
|
|
55
51
|
/**
|
|
56
52
|
* How the hook should behave when rendering client-side for the first time.
|
|
57
53
|
*
|
|
@@ -62,8 +58,7 @@ type HydratableEffectOptions<TData: ValidCacheData> = {|
|
|
|
62
58
|
* Changing this value after the first call is irrelevant as it only
|
|
63
59
|
* affects the initial render behavior.
|
|
64
60
|
*/
|
|
65
|
-
clientBehavior?: WhenClientSide
|
|
66
|
-
|
|
61
|
+
clientBehavior?: typeof WhenClientSide[keyof typeof WhenClientSide];
|
|
67
62
|
/**
|
|
68
63
|
* When `true`, the effect will not be executed; otherwise, the effect will
|
|
69
64
|
* be executed.
|
|
@@ -73,8 +68,7 @@ type HydratableEffectOptions<TData: ValidCacheData> = {|
|
|
|
73
68
|
*
|
|
74
69
|
* Default is `false`.
|
|
75
70
|
*/
|
|
76
|
-
skip?: boolean
|
|
77
|
-
|
|
71
|
+
skip?: boolean;
|
|
78
72
|
/**
|
|
79
73
|
* When `true`, the effect will not reset the result to the loading status
|
|
80
74
|
* while executing if the requestId changes, instead, returning
|
|
@@ -85,8 +79,7 @@ type HydratableEffectOptions<TData: ValidCacheData> = {|
|
|
|
85
79
|
* loading; old pending effects are discarded on changes and as such this
|
|
86
80
|
* value has no effect in that case.
|
|
87
81
|
*/
|
|
88
|
-
retainResultOnChange?: boolean
|
|
89
|
-
|
|
82
|
+
retainResultOnChange?: boolean;
|
|
90
83
|
/**
|
|
91
84
|
* Callback that is invoked if the result for the given hook has changed.
|
|
92
85
|
*
|
|
@@ -97,8 +90,7 @@ type HydratableEffectOptions<TData: ValidCacheData> = {|
|
|
|
97
90
|
* When not defined, the hook will ensure the component re-renders to pick
|
|
98
91
|
* up the latest result.
|
|
99
92
|
*/
|
|
100
|
-
onResultChanged?: (result: Result<TData>) => void
|
|
101
|
-
|
|
93
|
+
onResultChanged?: (result: Result<TData>) => void;
|
|
102
94
|
/**
|
|
103
95
|
* Scope to use with the shared cache.
|
|
104
96
|
*
|
|
@@ -107,8 +99,8 @@ type HydratableEffectOptions<TData: ValidCacheData> = {|
|
|
|
107
99
|
*
|
|
108
100
|
* Changing this value after the first call is not supported.
|
|
109
101
|
*/
|
|
110
|
-
scope?: string
|
|
111
|
-
|
|
102
|
+
scope?: string;
|
|
103
|
+
};
|
|
112
104
|
|
|
113
105
|
const DefaultScope = "useHydratableEffect";
|
|
114
106
|
|
|
@@ -122,12 +114,12 @@ const DefaultScope = "useHydratableEffect";
|
|
|
122
114
|
* invocations. Cache changes from one hook instance do not trigger renders
|
|
123
115
|
* in components that use the same requestID.
|
|
124
116
|
*/
|
|
125
|
-
export const useHydratableEffect = <TData
|
|
117
|
+
export const useHydratableEffect = <TData extends ValidCacheData>(
|
|
126
118
|
requestId: string,
|
|
127
119
|
handler: () => Promise<TData>,
|
|
128
|
-
options: HydratableEffectOptions<TData> =
|
|
129
|
-
HydratableEffectOptions<TData
|
|
130
|
-
|
|
120
|
+
options: HydratableEffectOptions<TData> = {} as Partial<
|
|
121
|
+
HydratableEffectOptions<TData>
|
|
122
|
+
>,
|
|
131
123
|
): Result<TData> => {
|
|
132
124
|
const {
|
|
133
125
|
clientBehavior = WhenClientSide.ExecuteWhenNoSuccessResult,
|
|
@@ -146,48 +138,49 @@ export const useHydratableEffect = <TData: ValidCacheData>(
|
|
|
146
138
|
skip,
|
|
147
139
|
});
|
|
148
140
|
|
|
149
|
-
const getDefaultCacheValue: () =>
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
// cache, will then prevent the cached effect running.
|
|
164
|
-
return serverResult;
|
|
165
|
-
|
|
166
|
-
case WhenClientSide.ExecuteWhenNoSuccessResult:
|
|
167
|
-
// We only execute if we didn't hydrate a success result.
|
|
168
|
-
if (serverResult?.status === "success") {
|
|
141
|
+
const getDefaultCacheValue: () => Result<TData> | null | undefined =
|
|
142
|
+
React.useCallback(() => {
|
|
143
|
+
// If we don't have a requestId, it's our first render, the one
|
|
144
|
+
// where we hydrated. So defer to our clientBehavior value.
|
|
145
|
+
switch (clientBehavior) {
|
|
146
|
+
case WhenClientSide.DoNotHydrate:
|
|
147
|
+
case WhenClientSide.AlwaysExecute:
|
|
148
|
+
// Either we weren't hydrating at all, or we don't care
|
|
149
|
+
// if we hydrated something or not, either way, we're
|
|
150
|
+
// doing a request.
|
|
151
|
+
return null;
|
|
152
|
+
|
|
153
|
+
case WhenClientSide.ExecuteWhenNoResult:
|
|
154
|
+
// We only execute if we didn't hydrate something.
|
|
169
155
|
// So, returning the hydration result as default for our
|
|
170
156
|
// cache, will then prevent the cached effect running.
|
|
171
157
|
return serverResult;
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
158
|
+
|
|
159
|
+
case WhenClientSide.ExecuteWhenNoSuccessResult:
|
|
160
|
+
// We only execute if we didn't hydrate a success result.
|
|
161
|
+
if (serverResult?.status === "success") {
|
|
162
|
+
// So, returning the hydration result as default for our
|
|
163
|
+
// cache, will then prevent the cached effect running.
|
|
164
|
+
return serverResult;
|
|
165
|
+
}
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
// There is no reason for this to change after the first render,
|
|
169
|
+
// you might think, but the function closes around serverResult and if
|
|
170
|
+
// the requestId changes, it still returns the hydrate result of the
|
|
171
|
+
// first render of the previous requestId. This then means that the
|
|
172
|
+
// hydrate result is still the same, and the effect is not re-executed
|
|
173
|
+
// because the cache gets incorrectly defaulted.
|
|
174
|
+
// However, we don't want to bother doing anything with this on
|
|
175
|
+
// client behavior changing since that truly is irrelevant.
|
|
176
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
177
|
+
}, [serverResult]);
|
|
185
178
|
|
|
186
179
|
// Instead of using state, which would be local to just this hook instance,
|
|
187
180
|
// we use a shared in-memory cache.
|
|
188
|
-
useSharedCache<Result<TData>>(
|
|
189
|
-
requestId, // The
|
|
190
|
-
scope,
|
|
181
|
+
useSharedCache<Result<TData>>( // The key of the cached item
|
|
182
|
+
requestId, // The scope of the cached items
|
|
183
|
+
scope,
|
|
191
184
|
getDefaultCacheValue,
|
|
192
185
|
);
|
|
193
186
|
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
// @flow
|
|
2
1
|
import * as React from "react";
|
|
3
2
|
|
|
4
|
-
import InterceptContext from "../components/intercept-context
|
|
5
|
-
import type {ValidCacheData} from "../util/types
|
|
3
|
+
import InterceptContext from "../components/intercept-context";
|
|
4
|
+
import type {ValidCacheData} from "../util/types";
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
7
|
* Allow request handling to be intercepted.
|
|
@@ -16,7 +15,7 @@ import type {ValidCacheData} from "../util/types.js";
|
|
|
16
15
|
* an intercepted handler, and then invoke `useServerEffect` (or other things)
|
|
17
16
|
* with that intercepted handler.
|
|
18
17
|
*/
|
|
19
|
-
export const useRequestInterception = <TData
|
|
18
|
+
export const useRequestInterception = <TData extends ValidCacheData>(
|
|
20
19
|
requestId: string,
|
|
21
20
|
handler: () => Promise<TData>,
|
|
22
21
|
): (() => Promise<TData>) => {
|
|
@@ -32,6 +31,7 @@ export const useRequestInterception = <TData: ValidCacheData>(
|
|
|
32
31
|
// Call the interceptors from closest to furthest.
|
|
33
32
|
// If one returns a non-null result, then we keep that.
|
|
34
33
|
const interceptResponse = interceptors.reduceRight(
|
|
34
|
+
// @ts-expect-error [FEI-5019] - TS2769 - No overload matches this call.
|
|
35
35
|
(prev, interceptor) => {
|
|
36
36
|
if (prev != null) {
|
|
37
37
|
return prev;
|
|
@@ -42,8 +42,8 @@ export const useRequestInterception = <TData: ValidCacheData>(
|
|
|
42
42
|
);
|
|
43
43
|
// If nothing intercepted this request, invoke the original handler.
|
|
44
44
|
// NOTE: We can't guarantee all interceptors return the same type
|
|
45
|
-
// as our handler, so how can
|
|
46
|
-
//
|
|
45
|
+
// as our handler, so how can TypeScript know? Let's just suppress that.
|
|
46
|
+
// @ts-expect-error [FEI-5019] - TS2739 - Type '(requestId: string) => Promise<ValidCacheData | null | undefined> | null | undefined' is missing the following properties from type 'Promise<TData>': then, catch, finally, [Symbol.toStringTag]
|
|
47
47
|
return interceptResponse ?? handler();
|
|
48
48
|
}, [handler, interceptors, requestId]);
|
|
49
49
|
|
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
// @flow
|
|
2
1
|
import {Server} from "@khanacademy/wonder-blocks-core";
|
|
3
2
|
import {useContext} from "react";
|
|
4
|
-
import {TrackerContext} from "../util/request-tracking
|
|
5
|
-
import {SsrCache} from "../util/ssr-cache
|
|
6
|
-
import {resultFromCachedResponse} from "../util/result-from-cache-response
|
|
7
|
-
import {useRequestInterception} from "./use-request-interception
|
|
3
|
+
import {TrackerContext} from "../util/request-tracking";
|
|
4
|
+
import {SsrCache} from "../util/ssr-cache";
|
|
5
|
+
import {resultFromCachedResponse} from "../util/result-from-cache-response";
|
|
6
|
+
import {useRequestInterception} from "./use-request-interception";
|
|
8
7
|
|
|
9
|
-
import type {Result, ValidCacheData} from "../util/types
|
|
8
|
+
import type {Result, ValidCacheData} from "../util/types";
|
|
10
9
|
|
|
11
|
-
type ServerEffectOptions = {
|
|
10
|
+
type ServerEffectOptions = {
|
|
12
11
|
/**
|
|
13
12
|
* When `true`, the result of the effect when fulfilled using Wonder Blocks
|
|
14
13
|
* Data will be stored in the hydration cache for hydrating client-side;
|
|
@@ -20,16 +19,15 @@ type ServerEffectOptions = {|
|
|
|
20
19
|
*
|
|
21
20
|
* Default is `true`.
|
|
22
21
|
*/
|
|
23
|
-
hydrate?: boolean
|
|
24
|
-
|
|
22
|
+
hydrate?: boolean;
|
|
25
23
|
/**
|
|
26
24
|
* When `true`, the effect will not be tracked for fulfillment; otherwise,
|
|
27
25
|
* the effect will be tracked for fulfillment.
|
|
28
26
|
*
|
|
29
27
|
* Default is `false`.
|
|
30
28
|
*/
|
|
31
|
-
skip?: boolean
|
|
32
|
-
|
|
29
|
+
skip?: boolean;
|
|
30
|
+
};
|
|
33
31
|
|
|
34
32
|
/**
|
|
35
33
|
* Hook to perform an asynchronous action during server-side rendering.
|
|
@@ -46,11 +44,11 @@ type ServerEffectOptions = {|
|
|
|
46
44
|
*
|
|
47
45
|
* The asynchronous action is never invoked on the client-side.
|
|
48
46
|
*/
|
|
49
|
-
export const useServerEffect = <TData
|
|
47
|
+
export const useServerEffect = <TData extends ValidCacheData>(
|
|
50
48
|
requestId: string,
|
|
51
49
|
handler: () => Promise<TData>,
|
|
52
|
-
options: ServerEffectOptions =
|
|
53
|
-
):
|
|
50
|
+
options: ServerEffectOptions = {} as Partial<ServerEffectOptions>,
|
|
51
|
+
): Result<TData> | null | undefined => {
|
|
54
52
|
const {hydrate = true, skip = false} = options;
|
|
55
53
|
|
|
56
54
|
// Plug in to the request interception framework for code that wants
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
// @flow
|
|
2
1
|
import * as React from "react";
|
|
3
|
-
import {DataError, DataErrors} from "../util/data-error
|
|
4
|
-
import {ScopedInMemoryCache} from "../util/scoped-in-memory-cache
|
|
5
|
-
import type {ValidCacheData, ScopedCache} from "../util/types
|
|
2
|
+
import {DataError, DataErrors} from "../util/data-error";
|
|
3
|
+
import {ScopedInMemoryCache} from "../util/scoped-in-memory-cache";
|
|
4
|
+
import type {ValidCacheData, ScopedCache} from "../util/types";
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
7
|
* A function for inserting a value into the cache or clearing it.
|
|
9
8
|
*/
|
|
10
|
-
type CacheValueFn<TValue
|
|
9
|
+
type CacheValueFn<TValue extends ValidCacheData> = (
|
|
10
|
+
value?: TValue | null | undefined,
|
|
11
|
+
) => void;
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* This is the cache.
|
|
@@ -42,11 +43,15 @@ export const SharedCache: ScopedCache = cache;
|
|
|
42
43
|
* sure this toggling is optional - or we could use a callback argument, to
|
|
43
44
|
* achieve this on an as-needed basis.
|
|
44
45
|
*/
|
|
45
|
-
export const useSharedCache = <TValue
|
|
46
|
+
export const useSharedCache = <TValue extends ValidCacheData>(
|
|
46
47
|
id: string,
|
|
47
48
|
scope: string,
|
|
48
|
-
initialValue?:
|
|
49
|
-
|
|
49
|
+
initialValue?:
|
|
50
|
+
| TValue
|
|
51
|
+
| null
|
|
52
|
+
| undefined
|
|
53
|
+
| (() => TValue | null | undefined),
|
|
54
|
+
): [TValue | null | undefined, CacheValueFn<TValue>] => {
|
|
50
55
|
// Verify arguments.
|
|
51
56
|
if (!id || typeof id !== "string") {
|
|
52
57
|
throw new DataError(
|
|
@@ -65,7 +70,7 @@ export const useSharedCache = <TValue: ValidCacheData>(
|
|
|
65
70
|
// Memoize our APIs.
|
|
66
71
|
// This one allows callers to set or replace the cached value.
|
|
67
72
|
const cacheValue = React.useCallback(
|
|
68
|
-
(value
|
|
73
|
+
(value?: TValue | null) =>
|
|
69
74
|
value == null
|
|
70
75
|
? cache.purge(scope, id)
|
|
71
76
|
: cache.set(scope, id, value),
|
|
@@ -76,8 +81,8 @@ export const useSharedCache = <TValue: ValidCacheData>(
|
|
|
76
81
|
// since our last run through. Also, our cache does not know what type it
|
|
77
82
|
// stores, so we have to cast it to the type we're exporting. This is a
|
|
78
83
|
// dev time courtesy, rather than a runtime thing.
|
|
79
|
-
//
|
|
80
|
-
let currentValue:
|
|
84
|
+
// @ts-expect-error [FEI-5019] - TS2322 - Type 'ValidCacheData | null | undefined' is not assignable to type 'TValue | null | undefined'.
|
|
85
|
+
let currentValue: TValue | null | undefined = cache.get(scope, id);
|
|
81
86
|
|
|
82
87
|
// If we have an initial value, we need to add it to the cache
|
|
83
88
|
// and use it as our current value.
|