react-relay 17.0.0 → 18.1.0
Sign up to get free protection for your applications and to get access to all the features.
- package/ReactRelayContainerUtils.js.flow +2 -2
- package/ReactRelayContext.js +1 -1
- package/ReactRelayContext.js.flow +1 -1
- package/ReactRelayFragmentContainer.js.flow +2 -2
- package/ReactRelayPaginationContainer.js.flow +2 -2
- package/ReactRelayQueryRenderer.js.flow +1 -1
- package/ReactRelayQueryRendererContext.js.flow +1 -1
- package/ReactRelayRefetchContainer.js.flow +2 -2
- package/ReactRelayTypes.js.flow +45 -18
- package/__flowtests__/ReactRelayFragmentContainer-flowtest.js.flow +2 -2
- package/buildReactRelayContainer.js.flow +6 -5
- package/hooks.js +1 -1
- package/index.js +1 -1
- package/legacy.js +1 -1
- package/lib/relay-hooks/getConnectionState.js +47 -0
- package/lib/relay-hooks/legacy/FragmentResource.js +2 -6
- package/lib/relay-hooks/loadEntryPoint.js +8 -5
- package/lib/relay-hooks/loadQuery.js +2 -14
- package/lib/relay-hooks/readFragmentInternal.js +2 -4
- package/lib/relay-hooks/useEntryPointLoader.js +5 -8
- package/lib/relay-hooks/useFragment.js +4 -7
- package/lib/relay-hooks/useFragmentInternal.js +6 -484
- package/lib/relay-hooks/useFragmentInternal_CURRENT.js +477 -0
- package/lib/relay-hooks/useFragmentInternal_EXPERIMENTAL.js +499 -0
- package/lib/relay-hooks/useLazyLoadQuery.js +2 -5
- package/lib/relay-hooks/useLoadMoreFunction.js +10 -43
- package/lib/relay-hooks/useLoadMoreFunction_EXPERIMENTAL.js +130 -0
- package/lib/relay-hooks/usePreloadedQuery.js +6 -9
- package/lib/relay-hooks/useQueryLoader.js +9 -3
- package/lib/relay-hooks/useQueryLoader_EXPERIMENTAL.js +120 -0
- package/multi-actor/ActorChange.js.flow +1 -1
- package/package.json +3 -3
- package/react-relay-hooks.js +2 -2
- package/react-relay-hooks.min.js +2 -2
- package/react-relay-legacy.js +1 -1
- package/react-relay-legacy.min.js +1 -1
- package/react-relay.js +2 -2
- package/react-relay.min.js +2 -2
- package/relay-hooks/EntryPointTypes.flow.js.flow +35 -12
- package/relay-hooks/LazyLoadEntryPointContainer_DEPRECATED.react.js.flow +8 -4
- package/relay-hooks/MatchContainer.js.flow +1 -1
- package/relay-hooks/ProfilerContext.js.flow +1 -1
- package/relay-hooks/__flowtests__/EntryPointTypes/ExtractQueryTypes-flowtest.js.flow +43 -0
- package/relay-hooks/getConnectionState.js.flow +97 -0
- package/relay-hooks/legacy/FragmentResource.js.flow +2 -13
- package/relay-hooks/loadEntryPoint.js.flow +10 -4
- package/relay-hooks/loadQuery.js.flow +4 -28
- package/relay-hooks/prepareEntryPoint_DEPRECATED.js.flow +4 -1
- package/relay-hooks/readFragmentInternal.js.flow +1 -10
- package/relay-hooks/useEntryPointLoader.js.flow +3 -4
- package/relay-hooks/useFragment.js.flow +0 -5
- package/relay-hooks/useFragmentInternal.js.flow +19 -643
- package/relay-hooks/useFragmentInternal_CURRENT.js.flow +656 -0
- package/relay-hooks/useFragmentInternal_EXPERIMENTAL.js.flow +718 -0
- package/relay-hooks/useLazyLoadQuery.js.flow +0 -5
- package/relay-hooks/useLoadMoreFunction.js.flow +14 -80
- package/relay-hooks/useLoadMoreFunction_EXPERIMENTAL.js.flow +280 -0
- package/relay-hooks/usePaginationFragment.js.flow +1 -1
- package/relay-hooks/usePreloadedQuery.js.flow +0 -5
- package/relay-hooks/useQueryLoader.js.flow +28 -5
- package/relay-hooks/useQueryLoader_EXPERIMENTAL.js.flow +253 -0
@@ -0,0 +1,97 @@
|
|
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 {Direction, ReaderFragment} from 'relay-runtime';
|
15
|
+
|
16
|
+
const invariant = require('invariant');
|
17
|
+
const {ConnectionInterface, getValueAtPath} = require('relay-runtime');
|
18
|
+
|
19
|
+
function getConnectionState(
|
20
|
+
direction: Direction,
|
21
|
+
fragmentNode: ReaderFragment,
|
22
|
+
fragmentData: mixed,
|
23
|
+
connectionPathInFragmentData: $ReadOnlyArray<string | number>,
|
24
|
+
): {
|
25
|
+
cursor: ?string,
|
26
|
+
hasMore: boolean,
|
27
|
+
} {
|
28
|
+
const {
|
29
|
+
EDGES,
|
30
|
+
PAGE_INFO,
|
31
|
+
HAS_NEXT_PAGE,
|
32
|
+
HAS_PREV_PAGE,
|
33
|
+
END_CURSOR,
|
34
|
+
START_CURSOR,
|
35
|
+
} = ConnectionInterface.get();
|
36
|
+
const connection = getValueAtPath(fragmentData, connectionPathInFragmentData);
|
37
|
+
if (connection == null) {
|
38
|
+
return {cursor: null, hasMore: false};
|
39
|
+
}
|
40
|
+
|
41
|
+
invariant(
|
42
|
+
typeof connection === 'object',
|
43
|
+
'Relay: Expected connection in fragment `%s` to have been `null`, or ' +
|
44
|
+
'a plain object with %s and %s properties. Instead got `%s`.',
|
45
|
+
fragmentNode.name,
|
46
|
+
EDGES,
|
47
|
+
PAGE_INFO,
|
48
|
+
connection,
|
49
|
+
);
|
50
|
+
|
51
|
+
const edges = connection[EDGES];
|
52
|
+
const pageInfo = connection[PAGE_INFO];
|
53
|
+
if (edges == null || pageInfo == null) {
|
54
|
+
return {cursor: null, hasMore: false};
|
55
|
+
}
|
56
|
+
|
57
|
+
invariant(
|
58
|
+
Array.isArray(edges),
|
59
|
+
'Relay: Expected connection in fragment `%s` to have a plural `%s` field. ' +
|
60
|
+
'Instead got `%s`.',
|
61
|
+
fragmentNode.name,
|
62
|
+
EDGES,
|
63
|
+
edges,
|
64
|
+
);
|
65
|
+
invariant(
|
66
|
+
typeof pageInfo === 'object',
|
67
|
+
'Relay: Expected connection in fragment `%s` to have a `%s` field. ' +
|
68
|
+
'Instead got `%s`.',
|
69
|
+
fragmentNode.name,
|
70
|
+
PAGE_INFO,
|
71
|
+
pageInfo,
|
72
|
+
);
|
73
|
+
|
74
|
+
const cursor =
|
75
|
+
direction === 'forward'
|
76
|
+
? pageInfo[END_CURSOR] ?? null
|
77
|
+
: pageInfo[START_CURSOR] ?? null;
|
78
|
+
invariant(
|
79
|
+
cursor === null || typeof cursor === 'string',
|
80
|
+
'Relay: Expected page info for connection in fragment `%s` to have a ' +
|
81
|
+
'valid `%s`. Instead got `%s`.',
|
82
|
+
fragmentNode.name,
|
83
|
+
START_CURSOR,
|
84
|
+
cursor,
|
85
|
+
);
|
86
|
+
|
87
|
+
let hasMore;
|
88
|
+
if (direction === 'forward') {
|
89
|
+
hasMore = cursor != null && pageInfo[HAS_NEXT_PAGE] === true;
|
90
|
+
} else {
|
91
|
+
hasMore = cursor != null && pageInfo[HAS_PREV_PAGE] === true;
|
92
|
+
}
|
93
|
+
|
94
|
+
return {cursor, hasMore};
|
95
|
+
}
|
96
|
+
|
97
|
+
module.exports = getConnectionState;
|
@@ -452,7 +452,7 @@ class FragmentResourceImpl {
|
|
452
452
|
missingLiveResolverFields(snapshot)?.map(({liveStateID}) => {
|
453
453
|
const store = environment.getStore();
|
454
454
|
|
455
|
-
// $FlowFixMe[prop-missing] This is expected to be a
|
455
|
+
// $FlowFixMe[prop-missing] This is expected to be a RelayModernStore
|
456
456
|
return store.getLiveResolverPromise(liveStateID);
|
457
457
|
}) ?? [];
|
458
458
|
|
@@ -559,21 +559,12 @@ class FragmentResourceImpl {
|
|
559
559
|
_throwOrLogErrorsInSnapshot(snapshot: SingularOrPluralSnapshot) {
|
560
560
|
if (Array.isArray(snapshot)) {
|
561
561
|
snapshot.forEach(s => {
|
562
|
-
handlePotentialSnapshotErrors(
|
563
|
-
this._environment,
|
564
|
-
s.missingRequiredFields,
|
565
|
-
s.relayResolverErrors,
|
566
|
-
s.errorResponseFields,
|
567
|
-
s.selector.node.metadata?.throwOnFieldError ?? false,
|
568
|
-
);
|
562
|
+
handlePotentialSnapshotErrors(this._environment, s.errorResponseFields);
|
569
563
|
});
|
570
564
|
} else {
|
571
565
|
handlePotentialSnapshotErrors(
|
572
566
|
this._environment,
|
573
|
-
snapshot.missingRequiredFields,
|
574
|
-
snapshot.relayResolverErrors,
|
575
567
|
snapshot.errorResponseFields,
|
576
|
-
snapshot.selector.node.metadata?.throwOnFieldError ?? false,
|
577
568
|
);
|
578
569
|
}
|
579
570
|
}
|
@@ -773,8 +764,6 @@ class FragmentResourceImpl {
|
|
773
764
|
missingLiveResolverFields: currentSnapshot.missingLiveResolverFields,
|
774
765
|
seenRecords: currentSnapshot.seenRecords,
|
775
766
|
selector: currentSnapshot.selector,
|
776
|
-
missingRequiredFields: currentSnapshot.missingRequiredFields,
|
777
|
-
relayResolverErrors: currentSnapshot.relayResolverErrors,
|
778
767
|
errorResponseFields: currentSnapshot.errorResponseFields,
|
779
768
|
};
|
780
769
|
if (updatedData !== renderData) {
|
@@ -17,13 +17,15 @@ import type {
|
|
17
17
|
EnvironmentProviderOptions,
|
18
18
|
IEnvironmentProvider,
|
19
19
|
PreloadedEntryPoint,
|
20
|
+
PreloadedQuery,
|
20
21
|
} from './EntryPointTypes.flow';
|
21
22
|
|
22
23
|
const {loadQuery} = require('./loadQuery');
|
23
24
|
|
24
25
|
function loadEntryPoint<
|
25
26
|
TEntryPointParams: {...},
|
26
|
-
|
27
|
+
// $FlowExpectedError[unclear-type] Need any to make it supertype of all PreloadedQuery
|
28
|
+
TPreloadedQueries: {+[string]: PreloadedQuery<any>},
|
27
29
|
TPreloadedEntryPoints: {...},
|
28
30
|
TRuntimeProps: {...},
|
29
31
|
TExtraProps,
|
@@ -53,8 +55,12 @@ function loadEntryPoint<
|
|
53
55
|
if (queries != null) {
|
54
56
|
const queriesPropNames = Object.keys(queries);
|
55
57
|
queriesPropNames.forEach(queryPropName => {
|
58
|
+
const query = queries[queryPropName];
|
59
|
+
if (query == null) {
|
60
|
+
return;
|
61
|
+
}
|
56
62
|
const {environmentProviderOptions, options, parameters, variables} =
|
57
|
-
|
63
|
+
query;
|
58
64
|
|
59
65
|
const environment = environmentProvider.getEnvironment(
|
60
66
|
environmentProviderOptions,
|
@@ -86,11 +92,11 @@ function loadEntryPoint<
|
|
86
92
|
entryPointDescription;
|
87
93
|
preloadedEntryPoints[entryPointPropName] = loadEntryPoint<
|
88
94
|
_,
|
89
|
-
{
|
95
|
+
{},
|
90
96
|
{...},
|
91
97
|
{...},
|
92
98
|
mixed,
|
93
|
-
EntryPointComponent<{
|
99
|
+
EntryPointComponent<{}, {...}, {...}, mixed>,
|
94
100
|
_,
|
95
101
|
>(environmentProvider, nestedEntryPoint, nestedParams);
|
96
102
|
});
|
@@ -30,7 +30,6 @@ import type {
|
|
30
30
|
} from 'relay-runtime';
|
31
31
|
|
32
32
|
const invariant = require('invariant');
|
33
|
-
const React = require('react');
|
34
33
|
const {
|
35
34
|
__internal: {fetchQueryDeduped},
|
36
35
|
Observable,
|
@@ -41,30 +40,19 @@ const {
|
|
41
40
|
getRequest,
|
42
41
|
getRequestIdentifier,
|
43
42
|
} = require('relay-runtime');
|
44
|
-
const warning = require('warning');
|
45
43
|
|
46
|
-
let RenderDispatcher = null;
|
47
44
|
let fetchKey = 100001;
|
48
45
|
|
49
|
-
hook useTrackLoadQueryInRender() {
|
50
|
-
if (RenderDispatcher === null) {
|
51
|
-
// Flow does not know of React internals (rightly so), but we need to
|
52
|
-
// ensure here that this function isn't called inside render.
|
53
|
-
RenderDispatcher =
|
54
|
-
// $FlowFixMe[prop-missing]
|
55
|
-
React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
|
56
|
-
?.ReactCurrentDispatcher?.current;
|
57
|
-
}
|
58
|
-
}
|
59
|
-
|
60
46
|
type QueryType<T> =
|
61
47
|
T extends Query<infer V, infer D, infer RR>
|
62
48
|
? {
|
63
49
|
variables: V,
|
64
50
|
response: D,
|
65
51
|
rawResponse?: $NonMaybeType<RR>,
|
66
|
-
}
|
67
|
-
:
|
52
|
+
}
|
53
|
+
: [+t: T] extends [+t: PreloadableConcreteRequest<infer V>]
|
54
|
+
? V
|
55
|
+
: empty;
|
68
56
|
|
69
57
|
declare function loadQuery<
|
70
58
|
T,
|
@@ -87,17 +75,6 @@ function loadQuery<
|
|
87
75
|
options?: ?LoadQueryOptions,
|
88
76
|
environmentProviderOptions?: ?TEnvironmentProviderOptions,
|
89
77
|
): PreloadedQueryInner<TQuery, TEnvironmentProviderOptions> {
|
90
|
-
// This code ensures that we don't call loadQuery during render.
|
91
|
-
const CurrentDispatcher =
|
92
|
-
// $FlowFixMe[prop-missing]
|
93
|
-
React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
|
94
|
-
?.ReactCurrentDispatcher?.current;
|
95
|
-
warning(
|
96
|
-
RenderDispatcher == null || CurrentDispatcher !== RenderDispatcher,
|
97
|
-
'Relay: `%s` should not be called inside a React render function.',
|
98
|
-
options?.__nameForWarning ?? 'loadQuery',
|
99
|
-
);
|
100
|
-
|
101
78
|
// Every time you call loadQuery, we will generate a new fetchKey.
|
102
79
|
// This will ensure that every query reference that is created and
|
103
80
|
// passed to usePreloadedQuery is independently evaluated,
|
@@ -407,5 +384,4 @@ function loadQuery<
|
|
407
384
|
|
408
385
|
module.exports = {
|
409
386
|
loadQuery,
|
410
|
-
useTrackLoadQueryInRender,
|
411
387
|
};
|
@@ -16,13 +16,15 @@ import type {
|
|
16
16
|
EntryPointComponent,
|
17
17
|
EnvironmentProviderOptions,
|
18
18
|
IEnvironmentProvider,
|
19
|
+
PreloadedQuery,
|
19
20
|
} from './EntryPointTypes.flow';
|
20
21
|
|
21
22
|
const preloadQuery = require('./preloadQuery_DEPRECATED');
|
22
23
|
|
23
24
|
function prepareEntryPoint<
|
24
25
|
TEntryPointParams: {...},
|
25
|
-
|
26
|
+
// $FlowExpectedError[unclear-type] Need any to make it supertype of all PreloadedQuery
|
27
|
+
TPreloadedQueries: {+[string]: PreloadedQuery<any>},
|
26
28
|
TPreloadedEntryPoints: {...},
|
27
29
|
TRuntimeProps: {...},
|
28
30
|
TExtraProps,
|
@@ -59,6 +61,7 @@ function prepareEntryPoint<
|
|
59
61
|
environmentProviderOptions,
|
60
62
|
);
|
61
63
|
|
64
|
+
// $FlowFixMe[incompatible-type]
|
62
65
|
preloadedQueries[queryPropName] = preloadQuery<OperationType, mixed>(
|
63
66
|
environment,
|
64
67
|
parameters,
|
@@ -85,20 +85,11 @@ function handlePotentialSnapshotErrorsForState(
|
|
85
85
|
if (state.kind === 'singular') {
|
86
86
|
handlePotentialSnapshotErrors(
|
87
87
|
environment,
|
88
|
-
state.snapshot.missingRequiredFields,
|
89
|
-
state.snapshot.relayResolverErrors,
|
90
88
|
state.snapshot.errorResponseFields,
|
91
|
-
state.snapshot.selector.node.metadata?.throwOnFieldError ?? false,
|
92
89
|
);
|
93
90
|
} else if (state.kind === 'plural') {
|
94
91
|
for (const snapshot of state.snapshots) {
|
95
|
-
handlePotentialSnapshotErrors(
|
96
|
-
environment,
|
97
|
-
snapshot.missingRequiredFields,
|
98
|
-
snapshot.relayResolverErrors,
|
99
|
-
snapshot.errorResponseFields,
|
100
|
-
snapshot.selector.node.metadata?.throwOnFieldError ?? false,
|
101
|
-
);
|
92
|
+
handlePotentialSnapshotErrors(environment, snapshot.errorResponseFields);
|
102
93
|
}
|
103
94
|
}
|
104
95
|
}
|
@@ -17,10 +17,10 @@ import type {
|
|
17
17
|
EnvironmentProviderOptions,
|
18
18
|
IEnvironmentProvider,
|
19
19
|
PreloadedEntryPoint,
|
20
|
+
PreloadedQuery,
|
20
21
|
} from './EntryPointTypes.flow';
|
21
22
|
|
22
23
|
const loadEntryPoint = require('./loadEntryPoint');
|
23
|
-
const {useTrackLoadQueryInRender} = require('./loadQuery');
|
24
24
|
const useIsMountedRef = require('./useIsMountedRef');
|
25
25
|
const {useCallback, useEffect, useRef, useState} = require('react');
|
26
26
|
|
@@ -52,7 +52,8 @@ const initialNullEntryPointReferenceState = {kind: 'NullEntryPointReference'};
|
|
52
52
|
|
53
53
|
hook useLoadEntryPoint<
|
54
54
|
TEntryPointParams: {...},
|
55
|
-
|
55
|
+
// $FlowExpectedError[unclear-type] Need any to make it supertype of all PreloadedQuery
|
56
|
+
TPreloadedQueries: {+[string]: PreloadedQuery<any>},
|
56
57
|
TPreloadedEntryPoints: {...},
|
57
58
|
TRuntimeProps: {...},
|
58
59
|
TExtraProps,
|
@@ -102,8 +103,6 @@ hook useLoadEntryPoint<
|
|
102
103
|
* entry point references.
|
103
104
|
*/
|
104
105
|
|
105
|
-
useTrackLoadQueryInRender();
|
106
|
-
|
107
106
|
const initialEntryPointReferenceInternal =
|
108
107
|
options?.TEST_ONLY__initialEntryPointData?.entryPointReference ??
|
109
108
|
initialNullEntryPointReferenceState;
|
@@ -13,7 +13,6 @@
|
|
13
13
|
|
14
14
|
import type {Fragment, FragmentType, GraphQLTaggedNode} from 'relay-runtime';
|
15
15
|
|
16
|
-
const {useTrackLoadQueryInRender} = require('./loadQuery');
|
17
16
|
const useFragmentInternal = require('./useFragmentInternal');
|
18
17
|
const useStaticFragmentNodeWarning = require('./useStaticFragmentNodeWarning');
|
19
18
|
const {useDebugValue} = require('react');
|
@@ -49,10 +48,6 @@ declare hook useFragment<TFragmentType: FragmentType, TData>(
|
|
49
48
|
): ?TData;
|
50
49
|
|
51
50
|
hook useFragment(fragment: GraphQLTaggedNode, key: mixed): mixed {
|
52
|
-
// We need to use this hook in order to be able to track if
|
53
|
-
// loadQuery was called during render
|
54
|
-
useTrackLoadQueryInRender();
|
55
|
-
|
56
51
|
const fragmentNode = getFragment(fragment);
|
57
52
|
useStaticFragmentNodeWarning(fragmentNode, 'first argument of useFragment()');
|
58
53
|
const data = useFragmentInternal(fragmentNode, key, 'useFragment()');
|