react-relay 18.1.0 → 19.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/ReactRelayContainerUtils.js.flow +2 -2
- package/ReactRelayContext.js +1 -1
- package/ReactRelayFragmentContainer.js.flow +5 -10
- package/ReactRelayLoggingContext.js.flow +21 -0
- package/ReactRelayPaginationContainer.js.flow +8 -8
- package/ReactRelayRefetchContainer.js.flow +8 -8
- package/ReactRelayTypes.js.flow +18 -11
- package/__flowtests__/ReactRelayFragmentContainer-flowtest.js.flow +1 -8
- package/__flowtests__/ReactRelayPaginationContainer-flowtest.js.flow +2 -5
- package/__flowtests__/ReactRelayRefetchContainer-flowtest.js.flow +2 -5
- package/buildReactRelayContainer.js.flow +3 -3
- package/hooks.js +1 -1
- package/index.js +1 -1
- package/index.js.flow +3 -0
- package/legacy.js +1 -1
- package/lib/ReactRelayLoggingContext.js +6 -0
- package/lib/index.js +2 -0
- package/lib/relay-hooks/legacy/FragmentResource.js +4 -5
- package/lib/relay-hooks/legacy/useRefetchableFragmentNode.js +1 -1
- package/lib/relay-hooks/loadEntryPoint.js +3 -0
- package/lib/relay-hooks/loadQuery.js +9 -16
- package/lib/relay-hooks/preloadQuery_DEPRECATED.js +7 -2
- package/lib/relay-hooks/readFragmentInternal.js +2 -2
- package/lib/relay-hooks/useFragmentInternal_CURRENT.js +12 -8
- package/lib/relay-hooks/useFragmentInternal_EXPERIMENTAL.js +12 -8
- package/lib/relay-hooks/useLoadMoreFunction.js +3 -2
- package/lib/relay-hooks/useLoadMoreFunction_EXPERIMENTAL.js +3 -2
- package/lib/relay-hooks/usePaginationFragment.js +5 -1
- package/lib/relay-hooks/usePrefetchableForwardPaginationFragment.js +228 -0
- package/lib/relay-hooks/usePrefetchableForwardPaginationFragment_EXPERIMENTAL.js +227 -0
- package/lib/relay-hooks/useRefetchableFragmentInternal.js +3 -3
- package/lib/relay-hooks/useRelayLoggingContext.js +9 -0
- package/package.json +3 -3
- package/relay-hooks/EntryPointContainer.react.js.flow +13 -17
- package/relay-hooks/EntryPointTypes.flow.js.flow +7 -5
- package/relay-hooks/MatchContainer.js.flow +1 -1
- package/relay-hooks/legacy/FragmentResource.js.flow +5 -9
- package/relay-hooks/legacy/useBlockingPaginationFragment.js.flow +2 -17
- package/relay-hooks/legacy/useRefetchableFragmentNode.js.flow +1 -1
- package/relay-hooks/loadEntryPoint.js.flow +6 -0
- package/relay-hooks/loadQuery.js.flow +47 -39
- package/relay-hooks/preloadQuery_DEPRECATED.js.flow +18 -3
- package/relay-hooks/readFragmentInternal.js.flow +2 -5
- package/relay-hooks/useEntryPointLoader.js.flow +4 -2
- package/relay-hooks/useFragment.js.flow +1 -0
- package/relay-hooks/useFragmentInternal.js.flow +2 -0
- package/relay-hooks/useFragmentInternal_CURRENT.js.flow +27 -12
- package/relay-hooks/useFragmentInternal_EXPERIMENTAL.js.flow +29 -12
- package/relay-hooks/useLazyLoadQuery.js.flow +4 -4
- package/relay-hooks/useLoadMoreFunction.js.flow +7 -7
- package/relay-hooks/useLoadMoreFunction_EXPERIMENTAL.js.flow +5 -7
- package/relay-hooks/usePaginationFragment.js.flow +6 -10
- package/relay-hooks/usePrefetchableForwardPaginationFragment.js.flow +436 -0
- package/relay-hooks/usePrefetchableForwardPaginationFragment_EXPERIMENTAL.js.flow +435 -0
- package/relay-hooks/usePreloadedQuery.js.flow +1 -0
- package/relay-hooks/useQueryLoader.js.flow +5 -1
- package/relay-hooks/useQueryLoader_EXPERIMENTAL.js.flow +3 -1
- package/relay-hooks/useRefetchableFragment.js.flow +1 -0
- package/relay-hooks/useRefetchableFragmentInternal.js.flow +3 -3
- package/relay-hooks/useRelayLoggingContext.js.flow +21 -0
- package/relay-hooks/useStaticFragmentNodeWarning.js.flow +1 -0
- package/react-relay-hooks.js +0 -4
- package/react-relay-hooks.min.js +0 -9
- package/react-relay-legacy.js +0 -4
- package/react-relay-legacy.min.js +0 -9
- package/react-relay.js +0 -4
- package/react-relay.min.js +0 -9
@@ -22,29 +22,25 @@ const React = require('react');
|
|
22
22
|
const {useContext, useEffect} = require('react');
|
23
23
|
const warning = require('warning');
|
24
24
|
|
25
|
-
|
25
|
+
component EntryPointContainer<
|
26
26
|
// $FlowFixMe[unsupported-variance-annotation]
|
27
|
-
|
27
|
+
TRuntimeProps: {...},
|
28
|
+
TRenders: React.Node,
|
28
29
|
// $FlowFixMe[unsupported-variance-annotation]
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
// $FlowFixMe[unsupported-variance-annotation]
|
35
|
-
+TEntryPointComponent: EntryPointComponent<
|
36
|
-
TPreloadedQueries,
|
37
|
-
TPreloadedNestedEntryPoints,
|
30
|
+
TEntryPointComponent: EntryPointComponent<
|
31
|
+
// $FlowExpectedErrors[unclear-type] Use any to accept all kinds of EntryPointComponent
|
32
|
+
any,
|
33
|
+
// $FlowExpectedErrors[unclear-type] Use any to accept all kinds of EntryPointComponent
|
34
|
+
any,
|
38
35
|
TRuntimeProps,
|
39
|
-
|
36
|
+
// $FlowExpectedErrors[unclear-type] Use any to accept all kinds of EntryPointComponent
|
37
|
+
any,
|
38
|
+
TRenders,
|
40
39
|
>,
|
41
|
-
>(
|
42
|
-
entryPointReference,
|
43
|
-
props,
|
44
|
-
}: $ReadOnly<{
|
40
|
+
>(
|
45
41
|
entryPointReference: PreloadedEntryPoint<TEntryPointComponent>,
|
46
42
|
props: TRuntimeProps,
|
47
|
-
|
43
|
+
) renders TRenders {
|
48
44
|
warning(
|
49
45
|
entryPointReference.isDisposed === false,
|
50
46
|
'<EntryPointContainer>: Expected entryPointReference to not be disposed ' +
|
@@ -14,7 +14,7 @@
|
|
14
14
|
/* eslint-disable no-unused-vars */
|
15
15
|
|
16
16
|
import type {JSResourceReference} from 'JSResourceReference';
|
17
|
-
import type {
|
17
|
+
import type {ComponentType, ElementConfig} from 'react';
|
18
18
|
import type {
|
19
19
|
CacheConfig,
|
20
20
|
FetchPolicy,
|
@@ -36,6 +36,7 @@ export type PreloadFetchPolicy =
|
|
36
36
|
export type PreloadOptions = {
|
37
37
|
+fetchKey?: string | number,
|
38
38
|
+fetchPolicy?: ?PreloadFetchPolicy,
|
39
|
+
+includeIf?: ?boolean,
|
39
40
|
+networkCacheConfig?: ?CacheConfig,
|
40
41
|
};
|
41
42
|
|
@@ -178,14 +179,15 @@ export type EntryPointComponent<
|
|
178
179
|
TPreloadedEntryPoints = {},
|
179
180
|
TRuntimeProps = {},
|
180
181
|
TExtraProps = null,
|
181
|
-
|
182
|
-
|
182
|
+
TRenders: React.Node = React.Node,
|
183
|
+
> = component(
|
184
|
+
...EntryPointProps<
|
183
185
|
TPreloadedQueries,
|
184
186
|
TPreloadedEntryPoints,
|
185
187
|
TRuntimeProps,
|
186
188
|
TExtraProps,
|
187
|
-
|
188
|
-
|
189
|
+
>
|
190
|
+
) renders TRenders;
|
189
191
|
|
190
192
|
// Return type of the `getPreloadProps(...)` of the entry point
|
191
193
|
export type PreloadProps<
|
@@ -95,7 +95,7 @@ export type MatchPointer = {
|
|
95
95
|
|
96
96
|
export type MatchContainerProps<TProps: {...}, TFallback: React.Node> = {
|
97
97
|
+fallback?: ?TFallback,
|
98
|
-
+loader: (module: mixed) =>
|
98
|
+
+loader: (module: mixed) => component(...TProps),
|
99
99
|
+match: ?MatchPointer | ?TypenameOnlyPointer,
|
100
100
|
+props?: TProps,
|
101
101
|
};
|
@@ -22,7 +22,6 @@ import type {
|
|
22
22
|
RequestDescriptor,
|
23
23
|
Snapshot,
|
24
24
|
} from 'relay-runtime';
|
25
|
-
import type {MissingLiveResolverField} from 'relay-runtime/store/RelayStoreTypes';
|
26
25
|
|
27
26
|
const LRUCache = require('../LRUCache');
|
28
27
|
const {getQueryResourceForEnvironment} = require('../QueryResource');
|
@@ -98,7 +97,7 @@ function hasMissingClientEdges(snapshot: SingularOrPluralSnapshot): boolean {
|
|
98
97
|
|
99
98
|
function missingLiveResolverFields(
|
100
99
|
snapshot: SingularOrPluralSnapshot,
|
101
|
-
): ?$ReadOnlyArray<
|
100
|
+
): ?$ReadOnlyArray<DataID> {
|
102
101
|
if (Array.isArray(snapshot)) {
|
103
102
|
return snapshot
|
104
103
|
.map(s => s.missingLiveResolverFields)
|
@@ -449,7 +448,7 @@ class FragmentResourceImpl {
|
|
449
448
|
);
|
450
449
|
const parentQueryPromiseResultPromise = parentQueryPromiseResult?.promise; // for refinement
|
451
450
|
const missingResolverFieldPromises =
|
452
|
-
missingLiveResolverFields(snapshot)?.map(
|
451
|
+
missingLiveResolverFields(snapshot)?.map(liveStateID => {
|
453
452
|
const store = environment.getStore();
|
454
453
|
|
455
454
|
// $FlowFixMe[prop-missing] This is expected to be a RelayModernStore
|
@@ -559,13 +558,10 @@ class FragmentResourceImpl {
|
|
559
558
|
_throwOrLogErrorsInSnapshot(snapshot: SingularOrPluralSnapshot) {
|
560
559
|
if (Array.isArray(snapshot)) {
|
561
560
|
snapshot.forEach(s => {
|
562
|
-
handlePotentialSnapshotErrors(this._environment, s.
|
561
|
+
handlePotentialSnapshotErrors(this._environment, s.fieldErrors);
|
563
562
|
});
|
564
563
|
} else {
|
565
|
-
handlePotentialSnapshotErrors(
|
566
|
-
this._environment,
|
567
|
-
snapshot.errorResponseFields,
|
568
|
-
);
|
564
|
+
handlePotentialSnapshotErrors(this._environment, snapshot.fieldErrors);
|
569
565
|
}
|
570
566
|
}
|
571
567
|
|
@@ -764,7 +760,7 @@ class FragmentResourceImpl {
|
|
764
760
|
missingLiveResolverFields: currentSnapshot.missingLiveResolverFields,
|
765
761
|
seenRecords: currentSnapshot.seenRecords,
|
766
762
|
selector: currentSnapshot.selector,
|
767
|
-
|
763
|
+
fieldErrors: currentSnapshot.fieldErrors,
|
768
764
|
};
|
769
765
|
if (updatedData !== renderData) {
|
770
766
|
const result = getFragmentResult(
|
@@ -14,13 +14,7 @@
|
|
14
14
|
import type {LoadMoreFn, UseLoadMoreFunctionArgs} from '../useLoadMoreFunction';
|
15
15
|
import type {Options} from './useRefetchableFragmentNode';
|
16
16
|
import type {RefetchableFragment} from 'relay-runtime';
|
17
|
-
import type {
|
18
|
-
Disposable,
|
19
|
-
FragmentType,
|
20
|
-
GraphQLResponse,
|
21
|
-
Observer,
|
22
|
-
Variables,
|
23
|
-
} from 'relay-runtime';
|
17
|
+
import type {Disposable, FragmentType, Variables} from 'relay-runtime';
|
24
18
|
|
25
19
|
const useLoadMoreFunction = require('../useLoadMoreFunction');
|
26
20
|
const useStaticFragmentNodeWarning = require('../useStaticFragmentNodeWarning');
|
@@ -169,16 +163,7 @@ hook useBlockingPaginationFragment<
|
|
169
163
|
hook useLoadMore<TVariables: Variables>(args: {
|
170
164
|
disableStoreUpdates: () => void,
|
171
165
|
enableStoreUpdates: () => void,
|
172
|
-
...$Exact<
|
173
|
-
$Diff<
|
174
|
-
UseLoadMoreFunctionArgs,
|
175
|
-
{
|
176
|
-
observer: Observer<GraphQLResponse>,
|
177
|
-
onReset: () => void,
|
178
|
-
...
|
179
|
-
},
|
180
|
-
>,
|
181
|
-
>,
|
166
|
+
...$Exact<Omit<UseLoadMoreFunctionArgs, 'observer' | 'onReset'>>,
|
182
167
|
}): [LoadMoreFn<TVariables>, boolean, () => void] {
|
183
168
|
const {disableStoreUpdates, enableStoreUpdates, ...loadMoreArgs} = args;
|
184
169
|
const [requestPromise, setRequestPromise] = useState<null | Promise<mixed>>(
|
@@ -592,7 +592,7 @@ if (__DEV__) {
|
|
592
592
|
fragmentNode: ReaderFragment,
|
593
593
|
componentDisplayName: string,
|
594
594
|
): void {
|
595
|
-
if (previousIDAndTypename == null) {
|
595
|
+
if (previousIDAndTypename == null || refetchedFragmentRef == null) {
|
596
596
|
return;
|
597
597
|
}
|
598
598
|
const {ID_KEY} = require('relay-runtime');
|
@@ -62,6 +62,12 @@ function loadEntryPoint<
|
|
62
62
|
const {environmentProviderOptions, options, parameters, variables} =
|
63
63
|
query;
|
64
64
|
|
65
|
+
// $FlowFixMe[prop-missing] Exists for types that wrap EntryPoint
|
66
|
+
if (options?.includeIf === false) {
|
67
|
+
// don't preload this query since the includeIf is false
|
68
|
+
return;
|
69
|
+
}
|
70
|
+
|
65
71
|
const environment = environmentProvider.getEnvironment(
|
66
72
|
environmentProviderOptions,
|
67
73
|
);
|
@@ -28,13 +28,13 @@ import type {
|
|
28
28
|
RequestIdentifier,
|
29
29
|
RequestParameters,
|
30
30
|
} from 'relay-runtime';
|
31
|
+
import type {OperationAvailability} from 'relay-runtime/store/RelayStoreTypes';
|
31
32
|
|
32
33
|
const invariant = require('invariant');
|
33
34
|
const {
|
34
35
|
__internal: {fetchQueryDeduped},
|
35
36
|
Observable,
|
36
37
|
PreloadableQueryRegistry,
|
37
|
-
RelayFeatureFlags,
|
38
38
|
ReplaySubject,
|
39
39
|
createOperationDescriptor,
|
40
40
|
getRequest,
|
@@ -131,6 +131,7 @@ function loadQuery<
|
|
131
131
|
let didMakeNetworkRequest = false;
|
132
132
|
const makeNetworkRequest = (
|
133
133
|
params: RequestParameters,
|
134
|
+
checkOperation?: () => OperationAvailability,
|
134
135
|
): Observable<GraphQLResponse> => {
|
135
136
|
// N.B. this function is called synchronously or not at all
|
136
137
|
// didMakeNetworkRequest is safe to rely on in the returned value
|
@@ -140,34 +141,38 @@ function loadQuery<
|
|
140
141
|
// `source` observable is returned.
|
141
142
|
didMakeNetworkRequest = true;
|
142
143
|
|
143
|
-
let observable;
|
144
144
|
const subject = new ReplaySubject<GraphQLResponse>();
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
const network = environment.getNetwork();
|
165
|
-
return network.execute(params, variables, networkCacheConfig);
|
166
|
-
});
|
167
|
-
} else {
|
145
|
+
|
146
|
+
// Here, we are calling fetchQueryDeduped at the network layer level,
|
147
|
+
// which ensures that only a single network request is active for a given
|
148
|
+
// (environment, identifier) pair.
|
149
|
+
// Since network requests can be started /before/ we have the query ast
|
150
|
+
// necessary to process the results, we need to dedupe the raw requests
|
151
|
+
// separately from deduping the operation execution; specifically,
|
152
|
+
// if `loadQuery` is called multiple times before the query ast is available,
|
153
|
+
// we still want the network request to be deduped.
|
154
|
+
// - If a duplicate active network request is found, it will return an
|
155
|
+
// Observable that replays the events of the already active request.
|
156
|
+
// - If no duplicate active network request is found, it will call the fetchFn
|
157
|
+
// to start the request, and return an Observable that will replay
|
158
|
+
// the events from the network request.
|
159
|
+
// We provide an extra key to the identifier to distinguish deduping
|
160
|
+
// of raw network requests vs deduping of operation executions.
|
161
|
+
const identifier: RequestIdentifier =
|
162
|
+
'raw-network-request-' + getRequestIdentifier(params, variables);
|
163
|
+
const observable = fetchQueryDeduped(environment, identifier, () => {
|
168
164
|
const network = environment.getNetwork();
|
169
|
-
|
170
|
-
|
165
|
+
return network.execute(
|
166
|
+
params,
|
167
|
+
variables,
|
168
|
+
networkCacheConfig,
|
169
|
+
undefined,
|
170
|
+
undefined,
|
171
|
+
undefined,
|
172
|
+
undefined,
|
173
|
+
checkOperation,
|
174
|
+
);
|
175
|
+
});
|
171
176
|
|
172
177
|
const {unsubscribe} = observable.subscribe({
|
173
178
|
error(err) {
|
@@ -196,17 +201,15 @@ function loadQuery<
|
|
196
201
|
operation: OperationDescriptor,
|
197
202
|
fetchFn: () => Observable<GraphQLResponse>,
|
198
203
|
) => {
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
didMakeNetworkRequest = true;
|
209
|
-
}
|
204
|
+
// N.B. at this point, if we're calling execute with a query ast (OperationDescriptor),
|
205
|
+
// we are guaranteed to have started a network request. We set this to
|
206
|
+
// true here as well since `makeNetworkRequest` might get skipped in the case
|
207
|
+
// where the query ast is already available and the query executions get deduped.
|
208
|
+
// Even if the execution gets deduped below, we still wan't to return
|
209
|
+
// an observable that provides the replayed network events for the query,
|
210
|
+
// so we set this to true before deduping, to guarantee that the `source`
|
211
|
+
// observable is returned.
|
212
|
+
didMakeNetworkRequest = true;
|
210
213
|
|
211
214
|
// Here, we are calling fetchQueryDeduped, which ensures that only
|
212
215
|
// a single operation is active for a given (environment, identifier) pair,
|
@@ -255,13 +258,18 @@ function loadQuery<
|
|
255
258
|
// then we do nothing.
|
256
259
|
const shouldFetch =
|
257
260
|
fetchPolicy !== 'store-or-network' ||
|
261
|
+
// environment.check can trigger store updates through missing field handlers,
|
262
|
+
// short circuiting the check avoids unnecessary updates
|
258
263
|
environment.check(operation).status !== 'available';
|
259
264
|
|
260
265
|
if (shouldFetch) {
|
261
266
|
executeDeduped(operation, () => {
|
262
267
|
// N.B. Since we have the operation synchronously available here,
|
263
268
|
// we can immediately fetch and execute the operation.
|
264
|
-
const networkObservable = makeNetworkRequest(
|
269
|
+
const networkObservable = makeNetworkRequest(
|
270
|
+
concreteRequest.params,
|
271
|
+
() => environment.check(operation),
|
272
|
+
);
|
265
273
|
const executeObservable = executeWithNetworkSource(
|
266
274
|
operation,
|
267
275
|
networkObservable,
|
@@ -24,6 +24,7 @@ import type {
|
|
24
24
|
GraphQLResponse,
|
25
25
|
GraphQLTaggedNode,
|
26
26
|
IEnvironment,
|
27
|
+
OperationAvailability,
|
27
28
|
OperationType,
|
28
29
|
Subscription,
|
29
30
|
} from 'relay-runtime';
|
@@ -167,12 +168,17 @@ function preloadQueryDeduped<TQuery: OperationType>(
|
|
167
168
|
}`;
|
168
169
|
const prevQueryEntry = pendingQueries.get(cacheKey);
|
169
170
|
|
170
|
-
|
171
|
-
|
171
|
+
function checkOperation(): OperationAvailability {
|
172
|
+
return query != null
|
172
173
|
? environment.check(
|
173
174
|
createOperationDescriptor(query, variables, networkCacheConfig),
|
174
175
|
)
|
175
176
|
: {status: 'missing'};
|
177
|
+
}
|
178
|
+
const availability =
|
179
|
+
fetchPolicy === STORE_OR_NETWORK_DEFAULT
|
180
|
+
? checkOperation()
|
181
|
+
: {status: 'missing'};
|
176
182
|
|
177
183
|
let nextQueryEntry: ?PendingQueryEntry;
|
178
184
|
if (availability.status === 'available' && query != null) {
|
@@ -203,7 +209,16 @@ function preloadQueryDeduped<TQuery: OperationType>(
|
|
203
209
|
}
|
204
210
|
} else if (prevQueryEntry == null || prevQueryEntry.kind !== 'network') {
|
205
211
|
// Should fetch but we're not already fetching: fetch!
|
206
|
-
const source = network.execute(
|
212
|
+
const source = network.execute(
|
213
|
+
params,
|
214
|
+
variables,
|
215
|
+
networkCacheConfig,
|
216
|
+
null,
|
217
|
+
undefined,
|
218
|
+
undefined,
|
219
|
+
undefined,
|
220
|
+
checkOperation,
|
221
|
+
);
|
207
222
|
const subject = new ReplaySubject<GraphQLResponse>();
|
208
223
|
nextQueryEntry = {
|
209
224
|
cacheKey,
|
@@ -83,13 +83,10 @@ function handlePotentialSnapshotErrorsForState(
|
|
83
83
|
state: FragmentState,
|
84
84
|
): void {
|
85
85
|
if (state.kind === 'singular') {
|
86
|
-
handlePotentialSnapshotErrors(
|
87
|
-
environment,
|
88
|
-
state.snapshot.errorResponseFields,
|
89
|
-
);
|
86
|
+
handlePotentialSnapshotErrors(environment, state.snapshot.fieldErrors);
|
90
87
|
} else if (state.kind === 'plural') {
|
91
88
|
for (const snapshot of state.snapshots) {
|
92
|
-
handlePotentialSnapshotErrors(environment, snapshot.
|
89
|
+
handlePotentialSnapshotErrors(environment, snapshot.fieldErrors);
|
93
90
|
}
|
94
91
|
}
|
95
92
|
}
|
@@ -48,7 +48,9 @@ type UseEntryPointLoaderHookReturnType<
|
|
48
48
|
type NullEntryPointReference = {
|
49
49
|
kind: 'NullEntryPointReference',
|
50
50
|
};
|
51
|
-
const initialNullEntryPointReferenceState = {
|
51
|
+
const initialNullEntryPointReferenceState: NullEntryPointReference = {
|
52
|
+
kind: 'NullEntryPointReference',
|
53
|
+
};
|
52
54
|
|
53
55
|
hook useLoadEntryPoint<
|
54
56
|
TEntryPointParams: {...},
|
@@ -122,7 +124,7 @@ hook useLoadEntryPoint<
|
|
122
124
|
|
123
125
|
const disposeEntryPoint = useCallback(() => {
|
124
126
|
if (isMountedRef.current) {
|
125
|
-
const nullEntryPointReference = {
|
127
|
+
const nullEntryPointReference: NullEntryPointReference = {
|
126
128
|
kind: 'NullEntryPointReference',
|
127
129
|
};
|
128
130
|
undisposedEntryPointReferencesRef.current.add(nullEntryPointReference);
|
@@ -54,6 +54,7 @@ hook useFragment(fragment: GraphQLTaggedNode, key: mixed): mixed {
|
|
54
54
|
if (__DEV__) {
|
55
55
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
56
56
|
// $FlowFixMe[react-rule-hook]
|
57
|
+
// $FlowFixMe[react-rule-hook-conditional]
|
57
58
|
useDebugValue({fragment: fragmentNode.name, data});
|
58
59
|
}
|
59
60
|
return data;
|
@@ -26,6 +26,7 @@ hook useFragmentInternal(
|
|
26
26
|
): ?SelectorData | Array<?SelectorData> {
|
27
27
|
if (RelayFeatureFlags.ENABLE_ACTIVITY_COMPATIBILITY) {
|
28
28
|
// $FlowFixMe[react-rule-hook] - the condition is static
|
29
|
+
// $FlowFixMe[react-rule-hook-conditional]
|
29
30
|
return useFragmentInternal_EXPERIMENTAL(
|
30
31
|
fragmentNode,
|
31
32
|
fragmentRef,
|
@@ -34,6 +35,7 @@ hook useFragmentInternal(
|
|
34
35
|
);
|
35
36
|
}
|
36
37
|
// $FlowFixMe[react-rule-hook] - the condition is static
|
38
|
+
// $FlowFixMe[react-rule-hook-conditional]
|
37
39
|
return useFragmentInternal_CURRENT(
|
38
40
|
fragmentNode,
|
39
41
|
fragmentRef,
|
@@ -14,6 +14,7 @@
|
|
14
14
|
import type {QueryResult} from './QueryResource';
|
15
15
|
import type {
|
16
16
|
CacheConfig,
|
17
|
+
DataID,
|
17
18
|
FetchPolicy,
|
18
19
|
IEnvironment,
|
19
20
|
ReaderFragment,
|
@@ -21,13 +22,11 @@ import type {
|
|
21
22
|
SelectorData,
|
22
23
|
Snapshot,
|
23
24
|
} from 'relay-runtime';
|
24
|
-
import type {
|
25
|
-
MissingClientEdgeRequestInfo,
|
26
|
-
MissingLiveResolverField,
|
27
|
-
} from 'relay-runtime/store/RelayStoreTypes';
|
25
|
+
import type {MissingClientEdgeRequestInfo} from 'relay-runtime/store/RelayStoreTypes';
|
28
26
|
|
29
27
|
const {getQueryResourceForEnvironment} = require('./QueryResource');
|
30
28
|
const useRelayEnvironment = require('./useRelayEnvironment');
|
29
|
+
const useRelayLoggingContext = require('./useRelayLoggingContext');
|
31
30
|
const invariant = require('invariant');
|
32
31
|
const {useDebugValue, useEffect, useMemo, useRef, useState} = require('react');
|
33
32
|
const {
|
@@ -89,13 +88,13 @@ function getMissingClientEdges(
|
|
89
88
|
|
90
89
|
function getSuspendingLiveResolver(
|
91
90
|
state: FragmentState,
|
92
|
-
): $ReadOnlyArray<
|
91
|
+
): $ReadOnlyArray<DataID> | null {
|
93
92
|
if (state.kind === 'bailout') {
|
94
93
|
return null;
|
95
94
|
} else if (state.kind === 'singular') {
|
96
95
|
return state.snapshot.missingLiveResolverFields ?? null;
|
97
96
|
} else {
|
98
|
-
let missingFields: null | Array<
|
97
|
+
let missingFields: null | Array<DataID> = null;
|
99
98
|
for (const snapshot of state.snapshots) {
|
100
99
|
if (snapshot.missingLiveResolverFields) {
|
101
100
|
missingFields = missingFields ?? [];
|
@@ -111,15 +110,21 @@ function getSuspendingLiveResolver(
|
|
111
110
|
function handlePotentialSnapshotErrorsForState(
|
112
111
|
environment: IEnvironment,
|
113
112
|
state: FragmentState,
|
113
|
+
loggingContext: mixed | void,
|
114
114
|
): void {
|
115
115
|
if (state.kind === 'singular') {
|
116
116
|
handlePotentialSnapshotErrors(
|
117
117
|
environment,
|
118
|
-
state.snapshot.
|
118
|
+
state.snapshot.fieldErrors,
|
119
|
+
loggingContext,
|
119
120
|
);
|
120
121
|
} else if (state.kind === 'plural') {
|
121
122
|
for (const snapshot of state.snapshots) {
|
122
|
-
handlePotentialSnapshotErrors(
|
123
|
+
handlePotentialSnapshotErrors(
|
124
|
+
environment,
|
125
|
+
snapshot.fieldErrors,
|
126
|
+
loggingContext,
|
127
|
+
);
|
123
128
|
}
|
124
129
|
}
|
125
130
|
}
|
@@ -155,7 +160,7 @@ function handleMissedUpdates(
|
|
155
160
|
missingLiveResolverFields: currentSnapshot.missingLiveResolverFields,
|
156
161
|
seenRecords: currentSnapshot.seenRecords,
|
157
162
|
selector: currentSnapshot.selector,
|
158
|
-
|
163
|
+
fieldErrors: currentSnapshot.fieldErrors,
|
159
164
|
};
|
160
165
|
return [
|
161
166
|
updatedData !== state.snapshot.data,
|
@@ -179,7 +184,7 @@ function handleMissedUpdates(
|
|
179
184
|
missingLiveResolverFields: currentSnapshot.missingLiveResolverFields,
|
180
185
|
seenRecords: currentSnapshot.seenRecords,
|
181
186
|
selector: currentSnapshot.selector,
|
182
|
-
|
187
|
+
fieldErrors: currentSnapshot.fieldErrors,
|
183
188
|
};
|
184
189
|
if (updatedData !== snapshot.data) {
|
185
190
|
didMissUpdates = true;
|
@@ -405,6 +410,12 @@ hook useFragmentInternal(
|
|
405
410
|
);
|
406
411
|
|
407
412
|
const environment = useRelayEnvironment();
|
413
|
+
let loggerContext;
|
414
|
+
if (RelayFeatureFlags.ENABLE_UI_CONTEXT_ON_RELAY_LOGGER) {
|
415
|
+
// $FlowFixMe[react-rule-hook] - the condition is static
|
416
|
+
// $FlowFixMe[react-rule-hook-conditional]
|
417
|
+
loggerContext = useRelayLoggingContext();
|
418
|
+
}
|
408
419
|
const [_state, setState] = useState<FragmentState>(() =>
|
409
420
|
getFragmentState(environment, fragmentSelector),
|
410
421
|
);
|
@@ -456,6 +467,7 @@ hook useFragmentInternal(
|
|
456
467
|
// always or never run for a given invocation of this hook.
|
457
468
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
458
469
|
// $FlowFixMe[react-rule-hook]
|
470
|
+
// $FlowFixMe[react-rule-hook-conditional]
|
459
471
|
const [clientEdgeQueries, activeRequestPromises] = useMemo(() => {
|
460
472
|
const missingClientEdges = getMissingClientEdges(state);
|
461
473
|
// eslint-disable-next-line no-shadow
|
@@ -487,6 +499,7 @@ hook useFragmentInternal(
|
|
487
499
|
// See above note
|
488
500
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
489
501
|
// $FlowFixMe[react-rule-hook]
|
502
|
+
// $FlowFixMe[react-rule-hook-conditional]
|
490
503
|
useEffect(() => {
|
491
504
|
const QueryResource = getQueryResourceForEnvironment(environment);
|
492
505
|
if (clientEdgeQueries?.length) {
|
@@ -508,7 +521,7 @@ hook useFragmentInternal(
|
|
508
521
|
const suspendingLiveResolvers = getSuspendingLiveResolver(state);
|
509
522
|
if (suspendingLiveResolvers != null && suspendingLiveResolvers.length > 0) {
|
510
523
|
throw Promise.all(
|
511
|
-
suspendingLiveResolvers.map(
|
524
|
+
suspendingLiveResolvers.map(liveStateID => {
|
512
525
|
// $FlowFixMe[prop-missing] This is expected to be a RelayModernStore
|
513
526
|
return environment.getStore().getLiveResolverPromise(liveStateID);
|
514
527
|
}),
|
@@ -543,7 +556,7 @@ hook useFragmentInternal(
|
|
543
556
|
|
544
557
|
// Report required fields only if we're not suspending, since that means
|
545
558
|
// they're missing even though we are out of options for possibly fetching them:
|
546
|
-
handlePotentialSnapshotErrorsForState(environment, state);
|
559
|
+
handlePotentialSnapshotErrorsForState(environment, state, loggerContext);
|
547
560
|
|
548
561
|
const hasPendingStateChanges = useRef<boolean>(false);
|
549
562
|
|
@@ -596,6 +609,7 @@ hook useFragmentInternal(
|
|
596
609
|
const fragmentRefIsNullish = fragmentRef == null; // for less sensitive memoization
|
597
610
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
598
611
|
// $FlowFixMe[react-rule-hook]
|
612
|
+
// $FlowFixMe[react-rule-hook-conditional]
|
599
613
|
data = useMemo(() => {
|
600
614
|
if (state.kind === 'bailout') {
|
601
615
|
// Bailout state can happen if the fragmentRef is a plural array that is empty or has no
|
@@ -647,6 +661,7 @@ hook useFragmentInternal(
|
|
647
661
|
if (__DEV__) {
|
648
662
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
649
663
|
// $FlowFixMe[react-rule-hook]
|
664
|
+
// $FlowFixMe[react-rule-hook-conditional]
|
650
665
|
useDebugValue({fragment: fragmentNode.name, data});
|
651
666
|
}
|
652
667
|
|