react-relay 15.0.0 → 16.0.0
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/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
|
}
|