react-relay 15.0.0 → 16.0.0
Sign up to get free protection for your applications and to get access to all the features.
- package/ReactRelayContext.js +1 -1
- package/ReactRelayQueryFetcher.js.flow +1 -5
- package/ReactRelayQueryRenderer.js.flow +9 -36
- package/ReactRelayTypes.js.flow +1 -0
- package/buildReactRelayContainer.js.flow +3 -1
- package/hooks.js +1 -1
- package/index.js +1 -1
- package/legacy.js +1 -1
- package/lib/ReactRelayContainerUtils.js +0 -11
- package/lib/ReactRelayContext.js +0 -11
- package/lib/ReactRelayFragmentContainer.js +6 -78
- package/lib/ReactRelayFragmentMockRenderer.js +0 -11
- package/lib/ReactRelayLocalQueryRenderer.js +0 -17
- package/lib/ReactRelayPaginationContainer.js +5 -208
- package/lib/ReactRelayQueryFetcher.js +2 -51
- package/lib/ReactRelayQueryRenderer.js +6 -94
- package/lib/ReactRelayQueryRendererContext.js +0 -11
- package/lib/ReactRelayRefetchContainer.js +5 -91
- package/lib/ReactRelayTestMocker.js +9 -85
- package/lib/ReactRelayTypes.js +0 -11
- package/lib/RelayContext.js +0 -21
- package/lib/assertFragmentMap.js +0 -15
- package/lib/buildReactRelayContainer.js +0 -19
- package/lib/getRootVariablesForFragments.js +0 -14
- package/lib/hooks.js +0 -15
- package/lib/index.js +0 -17
- package/lib/isRelayEnvironment.js +1 -18
- package/lib/jest-react/enqueueTask.js +0 -20
- package/lib/jest-react/internalAct.js +0 -38
- package/lib/legacy.js +0 -15
- package/lib/multi-actor/ActorChange.js +0 -11
- package/lib/multi-actor/index.js +0 -11
- package/lib/multi-actor/useRelayActorEnvironment.js +0 -11
- package/lib/relay-hooks/EntryPointContainer.react.js +0 -11
- package/lib/relay-hooks/EntryPointTypes.flow.js +1 -14
- package/lib/relay-hooks/FragmentResource.js +76 -132
- package/lib/relay-hooks/HooksImplementation.js +0 -11
- package/lib/relay-hooks/InternalLogger.js +0 -11
- package/lib/relay-hooks/LRUCache.js +0 -22
- package/lib/relay-hooks/LazyLoadEntryPointContainer_DEPRECATED.react.js +0 -18
- package/lib/relay-hooks/MatchContainer.js +0 -94
- package/lib/relay-hooks/NestedRelayEntryPointBuilderUtils.js +9 -0
- package/lib/relay-hooks/ProfilerContext.js +0 -15
- package/lib/relay-hooks/QueryResource.js +2 -68
- package/lib/relay-hooks/RelayEnvironmentProvider.js +0 -11
- package/lib/relay-hooks/SuspenseResource.js +0 -34
- package/lib/relay-hooks/loadEntryPoint.js +1 -24
- package/lib/relay-hooks/loadQuery.js +2 -106
- package/lib/relay-hooks/preloadQuery_DEPRECATED.js +2 -27
- package/lib/relay-hooks/prepareEntryPoint_DEPRECATED.js +0 -13
- package/lib/relay-hooks/react-cache/RelayReactCache.js +0 -12
- package/lib/relay-hooks/react-cache/getQueryResultOrFetchQuery_REACT_CACHE.js +1 -36
- package/lib/relay-hooks/react-cache/readFragmentInternal_REACT_CACHE.js +3 -27
- package/lib/relay-hooks/react-cache/useFragmentInternal_REACT_CACHE.js +34 -99
- package/lib/relay-hooks/react-cache/useFragment_REACT_CACHE.js +0 -15
- package/lib/relay-hooks/react-cache/useLazyLoadQuery_REACT_CACHE.js +0 -16
- package/lib/relay-hooks/react-cache/usePaginationFragment_REACT_CACHE.js +1 -23
- package/lib/relay-hooks/react-cache/usePreloadedQuery_REACT_CACHE.js +0 -29
- package/lib/relay-hooks/react-cache/useRefetchableFragmentInternal_REACT_CACHE.js +12 -96
- package/lib/relay-hooks/react-cache/useRefetchableFragment_REACT_CACHE.js +0 -14
- package/lib/relay-hooks/useBlockingPaginationFragment.js +0 -42
- package/lib/relay-hooks/useClientQuery.js +0 -18
- package/lib/relay-hooks/useEntryPointLoader.js +0 -69
- package/lib/relay-hooks/useFetchTrackingRef.js +0 -26
- package/lib/relay-hooks/useFragment.js +0 -17
- package/lib/relay-hooks/useFragmentNode.js +2 -32
- package/lib/relay-hooks/useIsMountedRef.js +0 -11
- package/lib/relay-hooks/useIsOperationNodeActive.js +0 -11
- package/lib/relay-hooks/useIsParentQueryActive.js +0 -11
- package/lib/relay-hooks/useLazyLoadQuery.js +0 -18
- package/lib/relay-hooks/useLazyLoadQueryNode.js +0 -35
- package/lib/relay-hooks/useLoadMoreFunction.js +9 -34
- package/lib/relay-hooks/useMemoOperationDescriptor.js +0 -11
- package/lib/relay-hooks/useMemoVariables.js +0 -17
- package/lib/relay-hooks/useMutation.js +0 -11
- package/lib/relay-hooks/usePaginationFragment.js +1 -26
- package/lib/relay-hooks/usePreloadedQuery.js +0 -27
- package/lib/relay-hooks/useQueryLoader.js +0 -74
- package/lib/relay-hooks/useRefetchableFragment.js +0 -16
- package/lib/relay-hooks/useRefetchableFragmentNode.js +14 -97
- package/lib/relay-hooks/useRelayEnvironment.js +0 -11
- package/lib/relay-hooks/useStaticFragmentNodeWarning.js +0 -15
- package/lib/relay-hooks/useSubscribeToInvalidationState.js +0 -25
- package/lib/relay-hooks/useSubscription.js +0 -15
- package/lib/relay-hooks/useUnsafeRef_DEPRECATED.js +0 -17
- package/package.json +2 -2
- package/react-relay-hooks.js +2 -2
- package/react-relay-hooks.min.js +2 -2
- package/react-relay-legacy.js +2 -2
- package/react-relay-legacy.min.js +2 -2
- package/react-relay.js +2 -2
- package/react-relay.min.js +2 -2
- package/relay-hooks/EntryPointContainer.react.js.flow +5 -0
- package/relay-hooks/EntryPointTypes.flow.js.flow +20 -19
- package/relay-hooks/FragmentResource.js.flow +114 -26
- package/relay-hooks/LazyLoadEntryPointContainer_DEPRECATED.react.js.flow +4 -2
- package/relay-hooks/NestedRelayEntryPointBuilderUtils.js.flow +51 -0
- package/relay-hooks/__flowtests__/EntryPointTypes/NestedEntrypoints-flowtest.js.flow +7 -5
- package/relay-hooks/__flowtests__/useBlockingPaginationFragment-flowtest.js.flow +5 -0
- package/relay-hooks/__flowtests__/usePaginationFragment-flowtest.js.flow +5 -0
- package/relay-hooks/__flowtests__/useRefetchableFragment-flowtest.js.flow +2 -0
- package/relay-hooks/loadEntryPoint.js.flow +4 -2
- package/relay-hooks/loadQuery.js.flow +21 -1
- package/relay-hooks/prepareEntryPoint_DEPRECATED.js.flow +4 -2
- package/relay-hooks/react-cache/readFragmentInternal_REACT_CACHE.js.flow +2 -1
- package/relay-hooks/react-cache/useFragmentInternal_REACT_CACHE.js.flow +28 -10
- package/relay-hooks/react-cache/useFragment_REACT_CACHE.js.flow +3 -9
- package/relay-hooks/react-cache/usePaginationFragment_REACT_CACHE.js.flow +28 -57
- package/relay-hooks/react-cache/useRefetchableFragmentInternal_REACT_CACHE.js.flow +19 -12
- package/relay-hooks/react-cache/useRefetchableFragment_REACT_CACHE.js.flow +15 -31
- package/relay-hooks/useBlockingPaginationFragment.js.flow +2 -4
- package/relay-hooks/useClientQuery.js.flow +2 -2
- package/relay-hooks/useFragmentNode.js.flow +2 -2
- package/relay-hooks/useLoadMoreFunction.js.flow +15 -9
- package/relay-hooks/useMutation.js.flow +26 -9
- package/relay-hooks/usePaginationFragment.js.flow +2 -8
- package/relay-hooks/useQueryLoader.js.flow +2 -8
- package/relay-hooks/useRefetchableFragment.js.flow +3 -2
- package/relay-hooks/useRefetchableFragmentNode.js.flow +28 -13
@@ -85,8 +85,10 @@ function prepareEntryPoint<
|
|
85
85
|
}
|
86
86
|
const preloadProps = entryPoint.getPreloadProps(entryPointParams);
|
87
87
|
const {queries, entryPoints, extraProps} = preloadProps;
|
88
|
-
|
89
|
-
const
|
88
|
+
// $FlowFixMe[incompatible-type]
|
89
|
+
const preloadedQueries: Partial<TPreloadedQueries> = {};
|
90
|
+
// $FlowFixMe[incompatible-type]
|
91
|
+
const preloadedEntryPoints: Partial<TPreloadedEntryPoints> = {};
|
90
92
|
if (queries != null) {
|
91
93
|
const queriesPropNames = Object.keys(queries);
|
92
94
|
queriesPropNames.forEach(queryPropName => {
|
@@ -0,0 +1,51 @@
|
|
1
|
+
/**
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
3
|
+
*
|
4
|
+
* This source code is licensed under the MIT license found in the
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
6
|
+
*
|
7
|
+
* @flow strict-local
|
8
|
+
* @format
|
9
|
+
* @oncall relay
|
10
|
+
*/
|
11
|
+
|
12
|
+
'use strict';
|
13
|
+
|
14
|
+
import type {
|
15
|
+
InternalEntryPointRepresentation,
|
16
|
+
ThinNestedEntryPointParams,
|
17
|
+
} from './EntryPointTypes.flow';
|
18
|
+
|
19
|
+
/**
|
20
|
+
* This is an identity function to construct a type safe nested entrypoint.
|
21
|
+
* By calling this function, we ensure that the type of entryPointParams matches
|
22
|
+
* exactly the type of preloadProps of the entrypoint.
|
23
|
+
*
|
24
|
+
* We make the type of `ThinNestedEntryPointParams` opaque, so that the only way
|
25
|
+
* to construct a `ThinNestedEntryPointParams` is by calling this function.
|
26
|
+
*/
|
27
|
+
declare function NestedRelayEntryPoint<
|
28
|
+
TEntryPointParams,
|
29
|
+
TPreloadedQueries,
|
30
|
+
TPreloadedEntryPoints,
|
31
|
+
TRuntimeProps,
|
32
|
+
TExtraProps,
|
33
|
+
>(
|
34
|
+
$ReadOnly<{
|
35
|
+
entryPoint: InternalEntryPointRepresentation<
|
36
|
+
TEntryPointParams,
|
37
|
+
TPreloadedQueries,
|
38
|
+
TPreloadedEntryPoints,
|
39
|
+
TRuntimeProps,
|
40
|
+
TExtraProps,
|
41
|
+
>,
|
42
|
+
entryPointParams: TEntryPointParams,
|
43
|
+
}>,
|
44
|
+
): ThinNestedEntryPointParams;
|
45
|
+
|
46
|
+
// eslint-disable-next-line no-redeclare
|
47
|
+
function NestedRelayEntryPoint<P>(params: P): P {
|
48
|
+
return params;
|
49
|
+
}
|
50
|
+
|
51
|
+
export {NestedRelayEntryPoint};
|
@@ -18,6 +18,8 @@ import type {
|
|
18
18
|
} from '../../EntryPointTypes.flow';
|
19
19
|
import type {JSResourceReference} from 'JSResourceReference';
|
20
20
|
|
21
|
+
import {NestedRelayEntryPoint} from '../../NestedRelayEntryPointBuilderUtils';
|
22
|
+
|
21
23
|
declare function mockJSResource<TModule>(
|
22
24
|
module: TModule,
|
23
25
|
): JSResourceReference<TModule>;
|
@@ -65,14 +67,14 @@ type BadParentEntrypointParams = $ReadOnly<{}>;
|
|
65
67
|
getPreloadProps(_params: BadParentEntrypointParams) {
|
66
68
|
return {
|
67
69
|
entryPoints: {
|
68
|
-
nestedComponent: {
|
69
|
-
entryPoint: NestedEntryPoint,
|
70
|
+
nestedComponent: NestedRelayEntryPoint({
|
70
71
|
/**
|
71
72
|
$FlowExpectedError The entryPointParams here should be of type
|
72
73
|
NestedEntrypointPreloadParams, but it does not contain subEntrypointPreloadParam
|
73
74
|
*/
|
75
|
+
entryPoint: NestedEntryPoint,
|
74
76
|
entryPointParams: Object.freeze({}),
|
75
|
-
},
|
77
|
+
}),
|
76
78
|
},
|
77
79
|
};
|
78
80
|
},
|
@@ -90,13 +92,13 @@ type GoodParentEntrypointParams = $ReadOnly<{}>;
|
|
90
92
|
getPreloadProps(_params: GoodParentEntrypointParams) {
|
91
93
|
return {
|
92
94
|
entryPoints: {
|
93
|
-
nestedComponent: {
|
95
|
+
nestedComponent: NestedRelayEntryPoint({
|
94
96
|
entryPoint: NestedEntryPoint,
|
95
97
|
// No flow error since this matches NestedEntrypointPreloadParams
|
96
98
|
entryPointParams: {
|
97
99
|
subEntrypointPreloadParam: 'test',
|
98
100
|
},
|
99
|
-
},
|
101
|
+
}),
|
100
102
|
},
|
101
103
|
};
|
102
104
|
},
|
@@ -45,6 +45,8 @@ type ExpectedReturnType<
|
|
45
45
|
/* eslint-disable react-hooks/rules-of-hooks */
|
46
46
|
|
47
47
|
// Nullability of returned data type is correct
|
48
|
+
// $FlowFixMe[prop-missing]
|
49
|
+
// $FlowFixMe[incompatible-cast]
|
48
50
|
(useBlockingPaginationFragment(
|
49
51
|
refetchableFragmentInput,
|
50
52
|
keyNonNullable,
|
@@ -112,9 +114,12 @@ const {loadNext} = useBlockingPaginationFragment(
|
|
112
114
|
);
|
113
115
|
// Accepts extraVariables
|
114
116
|
loadNext(10, {
|
117
|
+
// $FlowFixMe[prop-missing]
|
118
|
+
// $FlowFixMe[incompatible-call]
|
115
119
|
UNSTABLE_extraVariables: extraVariables,
|
116
120
|
});
|
117
121
|
|
122
|
+
// $FlowFixMe[prop-missing]
|
118
123
|
loadNext(10, {
|
119
124
|
// $FlowExpectedError: doesn't accept variables not available in the Flow type
|
120
125
|
UNSTABLE_extraVariables: invalidVariables,
|
@@ -47,6 +47,8 @@ type ExpectedReturnType<
|
|
47
47
|
/* eslint-disable react-hooks/rules-of-hooks */
|
48
48
|
|
49
49
|
// Nullability of returned data type is correct
|
50
|
+
// $FlowFixMe[prop-missing]
|
51
|
+
// $FlowFixMe[incompatible-cast]
|
50
52
|
(usePaginationFragment(
|
51
53
|
refetchableFragmentInput,
|
52
54
|
keyNonNullable,
|
@@ -113,9 +115,12 @@ const {loadNext} = usePaginationFragment(
|
|
113
115
|
);
|
114
116
|
// Accepts extraVariables
|
115
117
|
loadNext(10, {
|
118
|
+
// $FlowFixMe[prop-missing]
|
119
|
+
// $FlowFixMe[incompatible-call]
|
116
120
|
UNSTABLE_extraVariables: extraVariables,
|
117
121
|
});
|
118
122
|
|
123
|
+
// $FlowFixMe[prop-missing]
|
119
124
|
loadNext(10, {
|
120
125
|
// $FlowExpectedError: doesn't accept variables not available in the Flow type
|
121
126
|
UNSTABLE_extraVariables: invalidVariables,
|
@@ -31,6 +31,8 @@ import {
|
|
31
31
|
/* eslint-disable react-hooks/rules-of-hooks */
|
32
32
|
|
33
33
|
// Nullability of returned data type is correct
|
34
|
+
// $FlowFixMe[prop-missing]
|
35
|
+
// $FlowFixMe[incompatible-cast]
|
34
36
|
(useRefetchableFragment(refetchableFragmentInput, keyNonNullable): [
|
35
37
|
NonNullableData,
|
36
38
|
FetchFn<QueryVariablesSubset>,
|
@@ -46,8 +46,10 @@ function loadEntryPoint<
|
|
46
46
|
}
|
47
47
|
const preloadProps = entryPoint.getPreloadProps(entryPointParams);
|
48
48
|
const {queries, entryPoints, extraProps} = preloadProps;
|
49
|
-
|
50
|
-
const
|
49
|
+
// $FlowFixMe[incompatible-type]
|
50
|
+
const preloadedQueries: Partial<TPreloadedQueries> = {};
|
51
|
+
// $FlowFixMe[incompatible-type]
|
52
|
+
const preloadedEntryPoints: Partial<TPreloadedEntryPoints> = {};
|
51
53
|
if (queries != null) {
|
52
54
|
const queriesPropNames = Object.keys(queries);
|
53
55
|
queriesPropNames.forEach(queryPropName => {
|
@@ -24,6 +24,7 @@ import type {
|
|
24
24
|
IEnvironment,
|
25
25
|
OperationDescriptor,
|
26
26
|
OperationType,
|
27
|
+
Query,
|
27
28
|
RequestIdentifier,
|
28
29
|
RequestParameters,
|
29
30
|
} from 'relay-runtime';
|
@@ -56,12 +57,31 @@ function useTrackLoadQueryInRender() {
|
|
56
57
|
}
|
57
58
|
}
|
58
59
|
|
60
|
+
type QueryType<T> = T extends Query<infer V, infer D, infer RR>
|
61
|
+
? {
|
62
|
+
variables: V,
|
63
|
+
response: D,
|
64
|
+
rawResponse?: $NonMaybeType<RR>,
|
65
|
+
}
|
66
|
+
: $Call<<T>(PreloadableConcreteRequest<T>) => T, T>;
|
67
|
+
|
68
|
+
declare function loadQuery<
|
69
|
+
T,
|
70
|
+
TEnvironmentProviderOptions = EnvironmentProviderOptions,
|
71
|
+
>(
|
72
|
+
environment: IEnvironment,
|
73
|
+
preloadableRequest: T,
|
74
|
+
variables: QueryType<T>['variables'],
|
75
|
+
options?: ?LoadQueryOptions,
|
76
|
+
environmentProviderOptions?: ?TEnvironmentProviderOptions,
|
77
|
+
): PreloadedQueryInner<QueryType<T>, TEnvironmentProviderOptions>;
|
78
|
+
|
59
79
|
function loadQuery<
|
60
80
|
TQuery: OperationType,
|
61
81
|
TEnvironmentProviderOptions = EnvironmentProviderOptions,
|
62
82
|
>(
|
63
83
|
environment: IEnvironment,
|
64
|
-
preloadableRequest:
|
84
|
+
preloadableRequest: PreloadableConcreteRequest<TQuery>,
|
65
85
|
variables: TQuery['variables'],
|
66
86
|
options?: ?LoadQueryOptions,
|
67
87
|
environmentProviderOptions?: ?TEnvironmentProviderOptions,
|
@@ -45,8 +45,10 @@ function prepareEntryPoint<
|
|
45
45
|
}
|
46
46
|
const preloadProps = entryPoint.getPreloadProps(entryPointParams);
|
47
47
|
const {queries, entryPoints} = preloadProps;
|
48
|
-
|
49
|
-
const
|
48
|
+
// $FlowFixMe[incompatible-type]
|
49
|
+
const preloadedQueries: Partial<TPreloadedQueries> = {};
|
50
|
+
// $FlowFixMe[incompatible-type]
|
51
|
+
const preloadedEntryPoints: Partial<TPreloadedEntryPoints> = {};
|
50
52
|
if (queries != null) {
|
51
53
|
const queriesPropNames = Object.keys(queries);
|
52
54
|
queriesPropNames.forEach(queryPropName => {
|
@@ -27,6 +27,7 @@ const {getQueryResourceForEnvironment} = require('../QueryResource');
|
|
27
27
|
const invariant = require('invariant');
|
28
28
|
const {
|
29
29
|
__internal: {fetchQuery: fetchQueryInternal},
|
30
|
+
RelayFeatureFlags,
|
30
31
|
createOperationDescriptor,
|
31
32
|
getPendingOperationsForFragment,
|
32
33
|
getSelector,
|
@@ -268,7 +269,7 @@ function readFragmentInternal_REACT_CACHE(
|
|
268
269
|
data = state.snapshots.map(s => s.data);
|
269
270
|
}
|
270
271
|
|
271
|
-
if (__DEV__) {
|
272
|
+
if (RelayFeatureFlags.LOG_MISSING_RECORDS_IN_PROD || __DEV__) {
|
272
273
|
if (
|
273
274
|
fragmentRef != null &&
|
274
275
|
(data === undefined ||
|
@@ -32,6 +32,7 @@ const invariant = require('invariant');
|
|
32
32
|
const {useDebugValue, useEffect, useMemo, useRef, useState} = require('react');
|
33
33
|
const {
|
34
34
|
__internal: {fetchQuery: fetchQueryInternal},
|
35
|
+
RelayFeatureFlags,
|
35
36
|
areEqualSelectors,
|
36
37
|
createOperationDescriptor,
|
37
38
|
getPendingOperationsForFragment,
|
@@ -256,7 +257,17 @@ function subscribeToSnapshot(
|
|
256
257
|
prevState.kind !== 'singular' ||
|
257
258
|
prevState.snapshot.selector !== latestSnapshot.selector
|
258
259
|
) {
|
259
|
-
|
260
|
+
const updates = handleMissedUpdates(environment, prevState);
|
261
|
+
if (updates != null) {
|
262
|
+
const [dataChanged, nextState] = updates;
|
263
|
+
environment.__log({
|
264
|
+
name: 'useFragment.subscription.missedUpdates',
|
265
|
+
hasDataChanges: dataChanged,
|
266
|
+
});
|
267
|
+
return dataChanged ? nextState : prevState;
|
268
|
+
} else {
|
269
|
+
return prevState;
|
270
|
+
}
|
260
271
|
}
|
261
272
|
return {
|
262
273
|
kind: 'singular',
|
@@ -279,7 +290,17 @@ function subscribeToSnapshot(
|
|
279
290
|
prevState.kind !== 'plural' ||
|
280
291
|
prevState.snapshots[index]?.selector !== latestSnapshot.selector
|
281
292
|
) {
|
282
|
-
|
293
|
+
const updates = handleMissedUpdates(environment, prevState);
|
294
|
+
if (updates != null) {
|
295
|
+
const [dataChanged, nextState] = updates;
|
296
|
+
environment.__log({
|
297
|
+
name: 'useFragment.subscription.missedUpdates',
|
298
|
+
hasDataChanges: dataChanged,
|
299
|
+
});
|
300
|
+
return dataChanged ? nextState : prevState;
|
301
|
+
} else {
|
302
|
+
return prevState;
|
303
|
+
}
|
283
304
|
}
|
284
305
|
const updated = [...prevState.snapshots];
|
285
306
|
updated[index] = latestSnapshot;
|
@@ -328,7 +349,6 @@ function useFragmentInternal_REACT_CACHE(
|
|
328
349
|
fragmentRef: mixed,
|
329
350
|
hookDisplayName: string,
|
330
351
|
queryOptions?: FragmentQueryOptions,
|
331
|
-
fragmentKey?: string,
|
332
352
|
): ?SelectorData | Array<?SelectorData> {
|
333
353
|
const fragmentSelector = useMemo(
|
334
354
|
() => getSelector(fragmentNode, fragmentRef),
|
@@ -343,7 +363,6 @@ function useFragmentInternal_REACT_CACHE(
|
|
343
363
|
'Relay: Expected fragment pointer%s for fragment `%s` to be ' +
|
344
364
|
'an array, instead got `%s`. Remove `@relay(plural: true)` ' +
|
345
365
|
'from fragment `%s` to allow the prop to be an object.',
|
346
|
-
fragmentKey != null ? ` for key \`${fragmentKey}\`` : '',
|
347
366
|
fragmentNode.name,
|
348
367
|
typeof fragmentRef,
|
349
368
|
fragmentNode.name,
|
@@ -354,7 +373,6 @@ function useFragmentInternal_REACT_CACHE(
|
|
354
373
|
'Relay: Expected fragment pointer%s for fragment `%s` not to be ' +
|
355
374
|
'an array, instead got `%s`. Add `@relay(plural: true)` ' +
|
356
375
|
'to fragment `%s` to allow the prop to be an array.',
|
357
|
-
fragmentKey != null ? ` for key \`${fragmentKey}\`` : '',
|
358
376
|
fragmentNode.name,
|
359
377
|
typeof fragmentRef,
|
360
378
|
fragmentNode.name,
|
@@ -378,7 +396,6 @@ function useFragmentInternal_REACT_CACHE(
|
|
378
396
|
fragmentNode.name,
|
379
397
|
hookDisplayName,
|
380
398
|
fragmentNode.name,
|
381
|
-
fragmentKey == null ? 'a fragment reference' : `the \`${fragmentKey}\``,
|
382
399
|
hookDisplayName,
|
383
400
|
);
|
384
401
|
|
@@ -505,11 +522,12 @@ function useFragmentInternal_REACT_CACHE(
|
|
505
522
|
throw pendingOperationsResult.promise;
|
506
523
|
}
|
507
524
|
}
|
508
|
-
// Report required fields only if we're not suspending, since that means
|
509
|
-
// they're missing even though we are out of options for possibly fetching them:
|
510
|
-
handlePotentialSnapshotErrorsForState(environment, state);
|
511
525
|
}
|
512
526
|
|
527
|
+
// Report required fields only if we're not suspending, since that means
|
528
|
+
// they're missing even though we are out of options for possibly fetching them:
|
529
|
+
handlePotentialSnapshotErrorsForState(environment, state);
|
530
|
+
|
513
531
|
useEffect(() => {
|
514
532
|
// Check for updates since the state was rendered
|
515
533
|
let currentState = subscribedState;
|
@@ -565,7 +583,7 @@ function useFragmentInternal_REACT_CACHE(
|
|
565
583
|
data = state.snapshot.data;
|
566
584
|
}
|
567
585
|
|
568
|
-
if (__DEV__) {
|
586
|
+
if (RelayFeatureFlags.LOG_MISSING_RECORDS_IN_PROD || __DEV__) {
|
569
587
|
if (
|
570
588
|
fragmentRef != null &&
|
571
589
|
(data === undefined ||
|
@@ -30,23 +30,17 @@ declare function useFragment<TFragmentType: FragmentType, TData>(
|
|
30
30
|
key: HasSpread<TFragmentType>,
|
31
31
|
): TData;
|
32
32
|
|
33
|
-
// if the key is nullable, return nullable value
|
34
|
-
declare function useFragment<TFragmentType: FragmentType, TData>(
|
35
|
-
fragment: Fragment<TFragmentType, TData>,
|
36
|
-
key: ?HasSpread<TFragmentType>,
|
37
|
-
): ?TData;
|
38
|
-
|
39
33
|
// if the key is a non-nullable array of keys, return non-nullable array
|
40
34
|
declare function useFragment<TFragmentType: FragmentType, TData>(
|
41
35
|
fragment: Fragment<TFragmentType, TData>,
|
42
36
|
key: $ReadOnlyArray<HasSpread<TFragmentType>>,
|
43
37
|
): TData;
|
44
38
|
|
45
|
-
// if the key is
|
39
|
+
// if the key is null/void, return null/void value
|
46
40
|
declare function useFragment<TFragmentType: FragmentType, TData>(
|
47
41
|
fragment: Fragment<TFragmentType, TData>,
|
48
|
-
key:
|
49
|
-
):
|
42
|
+
key: null | void,
|
43
|
+
): null | void;
|
50
44
|
|
51
45
|
function useFragment(fragment: GraphQLTaggedNode, key: mixed): mixed {
|
52
46
|
// We need to use this hook in order to be able to track if
|
@@ -12,17 +12,15 @@
|
|
12
12
|
'use strict';
|
13
13
|
|
14
14
|
import type {LoadMoreFn, UseLoadMoreFunctionArgs} from '../useLoadMoreFunction';
|
15
|
+
import type {ReturnType} from '../usePaginationFragment';
|
15
16
|
import type {Options} from './useRefetchableFragmentInternal_REACT_CACHE';
|
16
|
-
import type {RefetchFnDynamic} from './useRefetchableFragmentInternal_REACT_CACHE';
|
17
17
|
import type {
|
18
18
|
FragmentType,
|
19
19
|
GraphQLResponse,
|
20
|
-
GraphQLTaggedNode,
|
21
20
|
Observer,
|
22
|
-
|
21
|
+
RefetchableFragment,
|
23
22
|
Variables,
|
24
23
|
} from 'relay-runtime';
|
25
|
-
import type {VariablesOf} from 'relay-runtime/util/RelayRuntimeTypes';
|
26
24
|
|
27
25
|
const useLoadMoreFunction = require('../useLoadMoreFunction');
|
28
26
|
const useRelayEnvironment = require('../useRelayEnvironment');
|
@@ -35,36 +33,15 @@ const {
|
|
35
33
|
getPaginationMetadata,
|
36
34
|
} = require('relay-runtime');
|
37
35
|
|
38
|
-
export type ReturnType<TQuery: OperationType, TKey, TFragmentData> = {
|
39
|
-
data: TFragmentData,
|
40
|
-
loadNext: LoadMoreFn<TQuery['variables']>,
|
41
|
-
loadPrevious: LoadMoreFn<TQuery['variables']>,
|
42
|
-
hasNext: boolean,
|
43
|
-
hasPrevious: boolean,
|
44
|
-
isLoadingNext: boolean,
|
45
|
-
isLoadingPrevious: boolean,
|
46
|
-
refetch: RefetchFnDynamic<TQuery, TKey>,
|
47
|
-
};
|
48
|
-
|
49
36
|
function usePaginationFragment<
|
50
|
-
|
51
|
-
|
37
|
+
TFragmentType: FragmentType,
|
38
|
+
TVariables: Variables,
|
39
|
+
TData,
|
40
|
+
TKey: ?{+$fragmentSpreads: TFragmentType, ...},
|
52
41
|
>(
|
53
|
-
fragmentInput:
|
42
|
+
fragmentInput: RefetchableFragment<TFragmentType, TData, TVariables>,
|
54
43
|
parentFragmentRef: TKey,
|
55
|
-
): ReturnType<
|
56
|
-
TQuery,
|
57
|
-
TKey,
|
58
|
-
// NOTE: This $Call ensures that the type of the returned data is either:
|
59
|
-
// - nullable if the provided ref type is nullable
|
60
|
-
// - non-nullable if the provided ref type is non-nullable
|
61
|
-
// prettier-ignore
|
62
|
-
$Call<
|
63
|
-
& (<TFragmentData>( { +$data?: TFragmentData, ... }) => TFragmentData)
|
64
|
-
& (<TFragmentData>(?{ +$data?: TFragmentData, ... }) => ?TFragmentData),
|
65
|
-
TKey,
|
66
|
-
>,
|
67
|
-
> {
|
44
|
+
): ReturnType<TVariables, TData, TKey> {
|
68
45
|
const fragmentNode = getFragment(fragmentInput);
|
69
46
|
useStaticFragmentNodeWarning(
|
70
47
|
fragmentNode,
|
@@ -72,22 +49,18 @@ function usePaginationFragment<
|
|
72
49
|
);
|
73
50
|
const componentDisplayName = 'usePaginationFragment()';
|
74
51
|
|
75
|
-
const {
|
76
|
-
|
77
|
-
paginationRequest,
|
78
|
-
paginationMetadata,
|
79
|
-
identifierField,
|
80
|
-
} = getPaginationMetadata(fragmentNode, componentDisplayName);
|
52
|
+
const {connectionPathInFragmentData, paginationRequest, paginationMetadata} =
|
53
|
+
getPaginationMetadata(fragmentNode, componentDisplayName);
|
81
54
|
|
82
55
|
const {fragmentData, fragmentRef, refetch} = useRefetchableFragmentInternal<
|
83
|
-
|
84
|
-
|
56
|
+
{variables: TVariables, response: TData},
|
57
|
+
{data?: TData},
|
85
58
|
>(fragmentNode, parentFragmentRef, componentDisplayName);
|
86
59
|
const fragmentIdentifier = getFragmentIdentifier(fragmentNode, fragmentRef);
|
87
60
|
|
88
61
|
// Backward pagination
|
89
62
|
const [loadPrevious, hasPrevious, isLoadingPrevious, disposeFetchPrevious] =
|
90
|
-
useLoadMore<
|
63
|
+
useLoadMore<TVariables>({
|
91
64
|
componentDisplayName,
|
92
65
|
connectionPathInFragmentData,
|
93
66
|
direction: 'backward',
|
@@ -95,29 +68,26 @@ function usePaginationFragment<
|
|
95
68
|
fragmentIdentifier,
|
96
69
|
fragmentNode,
|
97
70
|
fragmentRef,
|
98
|
-
identifierField,
|
99
71
|
paginationMetadata,
|
100
72
|
paginationRequest,
|
101
73
|
});
|
102
74
|
|
103
75
|
// Forward pagination
|
104
|
-
const [loadNext, hasNext, isLoadingNext, disposeFetchNext] =
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
paginationRequest,
|
117
|
-
});
|
76
|
+
const [loadNext, hasNext, isLoadingNext, disposeFetchNext] =
|
77
|
+
useLoadMore<TVariables>({
|
78
|
+
componentDisplayName,
|
79
|
+
connectionPathInFragmentData,
|
80
|
+
direction: 'forward',
|
81
|
+
fragmentData,
|
82
|
+
fragmentIdentifier,
|
83
|
+
fragmentNode,
|
84
|
+
fragmentRef,
|
85
|
+
paginationMetadata,
|
86
|
+
paginationRequest,
|
87
|
+
});
|
118
88
|
|
119
|
-
const refetchPagination
|
120
|
-
(variables:
|
89
|
+
const refetchPagination = useCallback(
|
90
|
+
(variables: TVariables, options: void | Options) => {
|
121
91
|
disposeFetchNext();
|
122
92
|
disposeFetchPrevious();
|
123
93
|
return refetch(variables, {...options, __environment: undefined});
|
@@ -137,6 +107,7 @@ function usePaginationFragment<
|
|
137
107
|
});
|
138
108
|
}
|
139
109
|
return {
|
110
|
+
// $FlowFixMe[incompatible-return]
|
140
111
|
data: fragmentData,
|
141
112
|
loadNext,
|
142
113
|
loadPrevious,
|
@@ -11,6 +11,7 @@
|
|
11
11
|
|
12
12
|
'use strict';
|
13
13
|
|
14
|
+
import type {RefetchableIdentifierInfo} from '../../../relay-runtime/util/ReaderNode';
|
14
15
|
import type {LoaderFn} from '../useQueryLoader';
|
15
16
|
import type {
|
16
17
|
ConcreteRequest,
|
@@ -98,7 +99,7 @@ type RefetchFnExact<TQuery: OperationType, TOptions = Options> = RefetchFnBase<
|
|
98
99
|
type RefetchFnInexact<
|
99
100
|
TQuery: OperationType,
|
100
101
|
TOptions = Options,
|
101
|
-
> = RefetchFnBase<Partial<VariablesOf<TQuery
|
102
|
+
> = RefetchFnBase<$ReadOnly<Partial<VariablesOf<TQuery>>>, TOptions>;
|
102
103
|
|
103
104
|
type Action =
|
104
105
|
| {
|
@@ -171,7 +172,7 @@ function useRefetchableFragmentNode<
|
|
171
172
|
componentDisplayName: string,
|
172
173
|
): ReturnType<TQuery, TKey, InternalOptions> {
|
173
174
|
const parentEnvironment = useRelayEnvironment();
|
174
|
-
const {refetchableRequest, fragmentRefPathInResponse,
|
175
|
+
const {refetchableRequest, fragmentRefPathInResponse, identifierInfo} =
|
175
176
|
getRefetchMetadata(fragmentNode, componentDisplayName);
|
176
177
|
const fragmentIdentifier = getFragmentIdentifier(
|
177
178
|
fragmentNode,
|
@@ -236,6 +237,7 @@ function useRefetchableFragmentNode<
|
|
236
237
|
debugPreviousIDAndTypename = debugFunctions.getInitialIDAndType(
|
237
238
|
refetchQuery.request.variables,
|
238
239
|
fragmentRefPathInResponse,
|
240
|
+
identifierInfo?.identifierQueryVariableName,
|
239
241
|
environment,
|
240
242
|
);
|
241
243
|
}
|
@@ -343,7 +345,7 @@ function useRefetchableFragmentNode<
|
|
343
345
|
fragmentIdentifier,
|
344
346
|
fragmentNode,
|
345
347
|
fragmentRefPathInResponse,
|
346
|
-
|
348
|
+
identifierInfo,
|
347
349
|
loadQuery,
|
348
350
|
parentFragmentRef,
|
349
351
|
refetchableRequest,
|
@@ -377,17 +379,17 @@ function useRefetchFunction<TQuery: OperationType>(
|
|
377
379
|
fragmentIdentifier: string,
|
378
380
|
fragmentNode: ReaderFragment,
|
379
381
|
fragmentRefPathInResponse: $ReadOnlyArray<string | number>,
|
380
|
-
|
382
|
+
identifierInfo: ?RefetchableIdentifierInfo,
|
381
383
|
loadQuery: LoaderFn<TQuery>,
|
382
384
|
parentFragmentRef: mixed,
|
383
385
|
refetchableRequest: ConcreteRequest,
|
384
386
|
): RefetchFn<TQuery, InternalOptions> {
|
385
387
|
const isMountedRef = useIsMountedRef();
|
386
388
|
const identifierValue =
|
387
|
-
identifierField != null &&
|
389
|
+
identifierInfo?.identifierField != null &&
|
388
390
|
fragmentData != null &&
|
389
391
|
typeof fragmentData === 'object'
|
390
|
-
? fragmentData[identifierField]
|
392
|
+
? fragmentData[identifierInfo.identifierField]
|
391
393
|
: null;
|
392
394
|
return useCallback(
|
393
395
|
(
|
@@ -454,8 +456,10 @@ function useRefetchFunction<TQuery: OperationType>(
|
|
454
456
|
// If the query needs an identifier value ('id' or similar) and one
|
455
457
|
// was not explicitly provided, read it from the fragment data.
|
456
458
|
if (
|
457
|
-
|
458
|
-
!providedRefetchVariables.hasOwnProperty(
|
459
|
+
identifierInfo != null &&
|
460
|
+
!providedRefetchVariables.hasOwnProperty(
|
461
|
+
identifierInfo.identifierQueryVariableName,
|
462
|
+
)
|
459
463
|
) {
|
460
464
|
// @refetchable fragments are guaranteed to have an `id` selection
|
461
465
|
// if the type is Node, implements Node, or is @fetchable. Double-check
|
@@ -465,11 +469,13 @@ function useRefetchFunction<TQuery: OperationType>(
|
|
465
469
|
false,
|
466
470
|
'Relay: Expected result to have a string ' +
|
467
471
|
'`%s` in order to refetch, got `%s`.',
|
468
|
-
identifierField,
|
472
|
+
identifierInfo.identifierField,
|
469
473
|
identifierValue,
|
470
474
|
);
|
471
475
|
}
|
472
|
-
(refetchVariables: $FlowFixMe)
|
476
|
+
(refetchVariables: $FlowFixMe)[
|
477
|
+
identifierInfo.identifierQueryVariableName
|
478
|
+
] = identifierValue;
|
473
479
|
}
|
474
480
|
|
475
481
|
const refetchQuery = createOperationDescriptor(
|
@@ -518,10 +524,11 @@ if (__DEV__) {
|
|
518
524
|
getInitialIDAndType(
|
519
525
|
memoRefetchVariables: ?Variables,
|
520
526
|
fragmentRefPathInResponse: $ReadOnlyArray<string | number>,
|
527
|
+
identifierQueryVariableName: ?string,
|
521
528
|
environment: IEnvironment,
|
522
529
|
): ?DebugIDandTypename {
|
523
530
|
const {Record} = require('relay-runtime');
|
524
|
-
const id = memoRefetchVariables?.id;
|
531
|
+
const id = memoRefetchVariables?.[identifierQueryVariableName ?? 'id'];
|
525
532
|
if (
|
526
533
|
fragmentRefPathInResponse.length !== 1 ||
|
527
534
|
fragmentRefPathInResponse[0] !== 'node' ||
|
@@ -531,7 +538,7 @@ if (__DEV__) {
|
|
531
538
|
}
|
532
539
|
const recordSource = environment.getStore().getSource();
|
533
540
|
const record = recordSource.get(id);
|
534
|
-
const typename = record
|
541
|
+
const typename = record == null ? null : Record.getType(record);
|
535
542
|
if (typename == null) {
|
536
543
|
return null;
|
537
544
|
}
|