react-relay 20.1.0 → 21.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/ReactRelayContext.js.flow +2 -2
- package/ReactRelayFragmentContainer.js.flow +9 -10
- package/ReactRelayLocalQueryRenderer.js.flow +11 -3
- package/ReactRelayLoggingContext.js.flow +3 -3
- package/ReactRelayPaginationContainer.js.flow +32 -25
- package/ReactRelayQueryFetcher.js.flow +1 -1
- package/ReactRelayQueryRenderer.js.flow +2 -2
- package/ReactRelayQueryRendererContext.js.flow +2 -2
- package/ReactRelayRefetchContainer.js.flow +18 -15
- package/ReactRelayTestMocker.js.flow +10 -10
- package/ReactRelayTypes.js.flow +18 -20
- package/RelayContext.js.flow +3 -3
- package/__flowtests__/ReactRelayFragmentContainer-flowtest.js.flow +11 -11
- package/__flowtests__/ReactRelayPaginationContainer-flowtest.js.flow +5 -5
- package/__flowtests__/ReactRelayRefetchContainer-flowtest.js.flow +5 -5
- package/__flowtests__/RelayModern-flowtest.js.flow +24 -27
- package/__flowtests__/RelayModernFlowtest_users.graphql.js.flow +1 -1
- package/__flowtests__/__generated__/ReactRelayFragmentContainerFlowtest_viewer.graphql.js.flow +3 -4
- package/__flowtests__/__generated__/ReactRelayFragmentContainerFlowtest_viewer2.graphql.js.flow +3 -4
- package/__flowtests__/__generated__/ReactRelayPaginationContainerFlowtestQuery.graphql.js.flow +9 -10
- package/__flowtests__/__generated__/ReactRelayPaginationContainerFlowtest_viewer.graphql.js.flow +4 -5
- package/__flowtests__/__generated__/ReactRelayRefetchContainerFlowtestQuery.graphql.js.flow +9 -10
- package/__flowtests__/__generated__/ReactRelayRefetchContainerFlowtest_viewer.graphql.js.flow +4 -5
- package/__flowtests__/__generated__/RelayModernFlowtest_badref.graphql.js.flow +3 -4
- package/__flowtests__/__generated__/RelayModernFlowtest_notref.graphql.js.flow +3 -4
- package/__flowtests__/__generated__/RelayModernFlowtest_user.graphql.js.flow +3 -4
- package/__flowtests__/__generated__/RelayModernFlowtest_users.graphql.js.flow +5 -6
- package/buildReactRelayContainer.js.flow +4 -4
- package/getRootVariablesForFragments.js.flow +3 -3
- package/hooks.js +1 -1
- package/hooks.js.flow +23 -8
- package/index.js +1 -1
- package/index.js.flow +40 -14
- package/isRelayEnvironment.js.flow +1 -1
- package/jest-react/internalAct.js.flow +1 -1
- package/legacy.js +1 -1
- package/legacy.js.flow +32 -13
- package/lib/ReactRelayFragmentContainer.js +1 -1
- package/lib/ReactRelayPaginationContainer.js +8 -8
- package/lib/ReactRelayRefetchContainer.js +8 -8
- package/lib/ReactRelayTestMocker.js +5 -5
- package/lib/hooks.js +18 -8
- package/lib/index.js +30 -14
- package/lib/legacy.js +26 -13
- package/lib/relay-hooks/legacy/useBlockingPaginationFragment.js +5 -5
- package/lib/relay-hooks/legacy/useRefetchableFragmentNode.js +34 -34
- package/lib/relay-hooks/loadEntryPoint.js +2 -2
- package/lib/relay-hooks/loadQuery.js +14 -14
- package/lib/relay-hooks/preloadQuery_DEPRECATED.js +10 -10
- package/lib/relay-hooks/readFragmentInternal.js +6 -6
- package/lib/relay-hooks/rsc/serverFetchQuery.js +20 -0
- package/lib/relay-hooks/rsc/serverPreloadQuery.js +31 -0
- package/lib/relay-hooks/rsc/serverReadFragment.js +15 -0
- package/lib/relay-hooks/rsc/useQueryFromServer.js +62 -0
- package/lib/relay-hooks/useFragmentInternal_CURRENT.js +49 -25
- package/lib/relay-hooks/useFragmentInternal_EXPERIMENTAL.js +81 -44
- package/lib/relay-hooks/useLazyLoadQueryNode.js +32 -19
- package/lib/relay-hooks/useMutation.js +6 -14
- package/lib/relay-hooks/useMutationAction_EXPERIMENTAL.js +26 -0
- package/lib/relay-hooks/usePreloadedQuery.js +52 -47
- package/lib/relay-hooks/useQueryLoader.js +2 -2
- package/lib/relay-hooks/useQueryLoader_EXPERIMENTAL.js +2 -2
- package/lib/relay-hooks/useRefetchableFragmentInternal.js +31 -31
- package/lib/rsc-client_EXPERIMENTAL.js +7 -0
- package/lib/rsc_EXPERIMENTAL.js +43 -0
- package/multi-actor/ActorChange.js.flow +1 -1
- package/package.json +3 -2
- package/relay-hooks/EntryPointContainer.react.js.flow +6 -6
- package/relay-hooks/EntryPointTypes.flow.js.flow +61 -67
- package/relay-hooks/LazyLoadEntryPointContainer_DEPRECATED.react.js.flow +23 -21
- package/relay-hooks/MatchContainer.js.flow +12 -6
- package/relay-hooks/NestedRelayEntryPointBuilderUtils.js.flow +3 -9
- package/relay-hooks/QueryResource.js.flow +6 -6
- package/relay-hooks/RelayEnvironmentProvider.js.flow +2 -2
- package/relay-hooks/__flowtests__/EntryPointTypes/EntryPointElementConfig-flowtest.js.flow +6 -6
- package/relay-hooks/__flowtests__/EntryPointTypes/ExtractQueryTypes-flowtest.js.flow +48 -1
- package/relay-hooks/__flowtests__/EntryPointTypes/NestedEntrypoints-flowtest.js.flow +9 -9
- package/relay-hooks/__flowtests__/__generated__/useFragmentFlowtest_user.graphql.js.flow +3 -4
- package/relay-hooks/__flowtests__/__generated__/useFragmentFlowtest_users.graphql.js.flow +5 -6
- package/relay-hooks/__flowtests__/useBlockingPaginationFragment-flowtest.js.flow +27 -32
- package/relay-hooks/__flowtests__/useFragment-flowtest.js.flow +25 -25
- package/relay-hooks/__flowtests__/usePaginationFragment-flowtest.js.flow +26 -32
- package/relay-hooks/__flowtests__/useRefetchableFragment-flowtest.js.flow +23 -30
- package/relay-hooks/__flowtests__/utils.js.flow +4 -4
- package/relay-hooks/getConnectionState.js.flow +4 -4
- package/relay-hooks/legacy/FragmentResource.js.flow +13 -13
- package/relay-hooks/legacy/useBlockingPaginationFragment.js.flow +24 -25
- package/relay-hooks/legacy/useFragmentNode.js.flow +4 -4
- package/relay-hooks/legacy/useRefetchableFragmentNode.js.flow +79 -81
- package/relay-hooks/loadEntryPoint.js.flow +16 -14
- package/relay-hooks/loadQuery.js.flow +18 -18
- package/relay-hooks/preloadQuery_DEPRECATED.js.flow +16 -13
- package/relay-hooks/prepareEntryPoint_DEPRECATED.js.flow +7 -7
- package/relay-hooks/readFragmentInternal.js.flow +9 -9
- package/relay-hooks/rsc/serverFetchQuery.js.flow +31 -0
- package/relay-hooks/rsc/serverPreloadQuery.js.flow +69 -0
- package/relay-hooks/rsc/serverReadFragment.js.flow +33 -0
- package/relay-hooks/rsc/useQueryFromServer.js.flow +135 -0
- package/relay-hooks/useClientQuery.js.flow +2 -2
- package/relay-hooks/useEntryPointLoader.js.flow +11 -11
- package/relay-hooks/useFragment.js.flow +7 -7
- package/relay-hooks/useFragmentInternal.js.flow +1 -1
- package/relay-hooks/useFragmentInternal_CURRENT.js.flow +54 -22
- package/relay-hooks/useFragmentInternal_EXPERIMENTAL.js.flow +95 -46
- package/relay-hooks/useIsOperationNodeActive.js.flow +1 -1
- package/relay-hooks/useIsParentQueryActive.js.flow +1 -1
- package/relay-hooks/useLazyLoadQuery.js.flow +10 -3
- package/relay-hooks/useLazyLoadQueryNode.js.flow +67 -28
- package/relay-hooks/useLoadMoreFunction.js.flow +7 -6
- package/relay-hooks/useLoadMoreFunction_EXPERIMENTAL.js.flow +5 -5
- package/relay-hooks/useMemoVariables.js.flow +1 -1
- package/relay-hooks/useMutation.js.flow +8 -16
- package/relay-hooks/useMutationAction_EXPERIMENTAL.js.flow +68 -0
- package/relay-hooks/usePaginationFragment.js.flow +15 -11
- package/relay-hooks/usePrefetchableForwardPaginationFragment.js.flow +19 -18
- package/relay-hooks/usePrefetchableForwardPaginationFragment_EXPERIMENTAL.js.flow +19 -18
- package/relay-hooks/usePreloadedQuery.js.flow +119 -85
- package/relay-hooks/useQueryLoader.js.flow +27 -23
- package/relay-hooks/useQueryLoader_EXPERIMENTAL.js.flow +10 -10
- package/relay-hooks/useRefetchableFragment.js.flow +16 -11
- package/relay-hooks/useRefetchableFragmentInternal.js.flow +77 -79
- package/relay-hooks/useRelayLoggingContext.js.flow +1 -1
- package/relay-hooks/useSubscribeToInvalidationState.js.flow +1 -1
- package/relay-hooks/useSubscription.js.flow +1 -1
- package/rsc-client_EXPERIMENTAL.js +10 -0
- package/rsc-client_EXPERIMENTAL.js.flow +23 -0
- package/rsc_EXPERIMENTAL.js +10 -0
- package/rsc_EXPERIMENTAL.js.flow +90 -0
|
@@ -17,6 +17,7 @@ import type {
|
|
|
17
17
|
Observable,
|
|
18
18
|
OperationDescriptor,
|
|
19
19
|
OperationType,
|
|
20
|
+
ReaderFragment,
|
|
20
21
|
RenderPolicy,
|
|
21
22
|
} from 'relay-runtime';
|
|
22
23
|
|
|
@@ -32,47 +33,74 @@ const React = require('react');
|
|
|
32
33
|
|
|
33
34
|
const {useContext, useEffect, useState, useRef} = React;
|
|
34
35
|
|
|
35
|
-
|
|
36
|
-
query,
|
|
37
|
-
componentDisplayName,
|
|
38
|
-
fetchObservable,
|
|
39
|
-
fetchPolicy,
|
|
40
|
-
fetchKey,
|
|
41
|
-
renderPolicy,
|
|
42
|
-
}: {
|
|
36
|
+
export type LazyLoadQueryNodeParamsWithQuery = Readonly<{
|
|
43
37
|
query: OperationDescriptor,
|
|
44
38
|
componentDisplayName: string,
|
|
45
39
|
fetchObservable: Observable<GraphQLResponse>,
|
|
46
40
|
fetchPolicy?: ?FetchPolicy,
|
|
47
41
|
fetchKey?: ?string | ?number,
|
|
48
42
|
renderPolicy?: ?RenderPolicy,
|
|
49
|
-
}
|
|
43
|
+
}>;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* This param will be used when the query key is not provided
|
|
47
|
+
* (e.g. in usePreloadedQuery)
|
|
48
|
+
*/
|
|
49
|
+
export type LazyLoadQueryNodeParamsWithoutQuery = Readonly<{
|
|
50
|
+
componentDisplayName: string,
|
|
51
|
+
fragmentNode: ReaderFragment,
|
|
52
|
+
}>;
|
|
53
|
+
|
|
54
|
+
export type LazyLoadQueryNodeParams =
|
|
55
|
+
| LazyLoadQueryNodeParamsWithQuery
|
|
56
|
+
| LazyLoadQueryNodeParamsWithoutQuery;
|
|
57
|
+
|
|
58
|
+
hook useLazyLoadQueryNode<
|
|
59
|
+
TQuery extends OperationType,
|
|
60
|
+
TParams extends LazyLoadQueryNodeParams = LazyLoadQueryNodeParams,
|
|
61
|
+
>(
|
|
62
|
+
params: TParams,
|
|
63
|
+
): TParams extends LazyLoadQueryNodeParamsWithQuery
|
|
64
|
+
? TQuery['response']
|
|
65
|
+
: null {
|
|
50
66
|
const environment = useRelayEnvironment();
|
|
51
67
|
const profilerContext = useContext(ProfilerContext);
|
|
52
68
|
const QueryResource = getQueryResourceForEnvironment(environment);
|
|
53
69
|
|
|
54
70
|
const [forceUpdateKey, forceUpdate] = useState(0);
|
|
55
71
|
const {startFetch, completeFetch} = useFetchTrackingRef();
|
|
56
|
-
const cacheBreaker = `${forceUpdateKey}-${fetchKey ?? ''}`;
|
|
57
|
-
const cacheIdentifier = getQueryCacheIdentifier(
|
|
58
|
-
environment,
|
|
59
|
-
query,
|
|
60
|
-
fetchPolicy,
|
|
61
|
-
renderPolicy,
|
|
62
|
-
cacheBreaker,
|
|
63
|
-
);
|
|
64
72
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
73
|
+
let cacheIdentifier = null;
|
|
74
|
+
let preparedQueryResult = null;
|
|
75
|
+
let fragmentNode;
|
|
76
|
+
if (params.query != null) {
|
|
77
|
+
const {query, fetchObservable, fetchPolicy, fetchKey, renderPolicy} =
|
|
78
|
+
params;
|
|
79
|
+
const cacheBreaker = `${forceUpdateKey}-${fetchKey ?? ''}`;
|
|
80
|
+
const queryCacheIdentifier = getQueryCacheIdentifier(
|
|
81
|
+
environment,
|
|
68
82
|
query,
|
|
69
|
-
fetchObservable,
|
|
70
83
|
fetchPolicy,
|
|
71
84
|
renderPolicy,
|
|
72
|
-
|
|
73
|
-
profilerContext,
|
|
85
|
+
cacheBreaker,
|
|
74
86
|
);
|
|
75
|
-
|
|
87
|
+
cacheIdentifier = queryCacheIdentifier;
|
|
88
|
+
|
|
89
|
+
preparedQueryResult = profilerContext.wrapPrepareQueryResource(() => {
|
|
90
|
+
return QueryResource.prepareWithIdentifier(
|
|
91
|
+
queryCacheIdentifier,
|
|
92
|
+
query,
|
|
93
|
+
fetchObservable,
|
|
94
|
+
fetchPolicy,
|
|
95
|
+
renderPolicy,
|
|
96
|
+
{start: startFetch, complete: completeFetch, error: completeFetch},
|
|
97
|
+
profilerContext,
|
|
98
|
+
);
|
|
99
|
+
});
|
|
100
|
+
fragmentNode = preparedQueryResult.fragmentNode;
|
|
101
|
+
} else {
|
|
102
|
+
fragmentNode = params.fragmentNode;
|
|
103
|
+
}
|
|
76
104
|
|
|
77
105
|
const maybeHiddenOrFastRefresh = useRef(false);
|
|
78
106
|
useEffect(() => {
|
|
@@ -103,6 +131,10 @@ hook useLazyLoadQueryNode<TQuery: OperationType>({
|
|
|
103
131
|
return;
|
|
104
132
|
}
|
|
105
133
|
|
|
134
|
+
if (preparedQueryResult == null) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
106
138
|
const disposable = QueryResource.retain(
|
|
107
139
|
preparedQueryResult,
|
|
108
140
|
profilerContext,
|
|
@@ -117,6 +149,10 @@ hook useLazyLoadQueryNode<TQuery: OperationType>({
|
|
|
117
149
|
}, [environment, cacheIdentifier]);
|
|
118
150
|
|
|
119
151
|
useEffect(() => {
|
|
152
|
+
if (preparedQueryResult == null) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
120
156
|
// Release any temporary retain that's not released. At this point, if the
|
|
121
157
|
// cacheIdentifier doesn't change, the query is still permanently retained,
|
|
122
158
|
// and the temporary retain is redundant.
|
|
@@ -124,13 +160,16 @@ hook useLazyLoadQueryNode<TQuery: OperationType>({
|
|
|
124
160
|
// This effect is intended to run on every commit, thus no dependency
|
|
125
161
|
});
|
|
126
162
|
|
|
127
|
-
const {fragmentNode, fragmentRef} = preparedQueryResult;
|
|
128
163
|
const data = useFragmentInternal(
|
|
129
164
|
fragmentNode,
|
|
130
|
-
fragmentRef,
|
|
131
|
-
componentDisplayName,
|
|
165
|
+
preparedQueryResult?.fragmentRef,
|
|
166
|
+
params.componentDisplayName,
|
|
132
167
|
);
|
|
133
|
-
|
|
168
|
+
|
|
169
|
+
// Flow is confused in understanding the conditional type.
|
|
170
|
+
// We know data is the query response if input params is LazyLoadQueryNodeParamsWithQuery,
|
|
171
|
+
// and void if otherwise.
|
|
172
|
+
return data as $FlowFixMe;
|
|
134
173
|
}
|
|
135
174
|
|
|
136
175
|
module.exports = useLazyLoadQueryNode;
|
|
@@ -40,7 +40,7 @@ const {
|
|
|
40
40
|
} = require('relay-runtime');
|
|
41
41
|
const warning = require('warning');
|
|
42
42
|
|
|
43
|
-
export type LoadMoreFn<TVariables
|
|
43
|
+
export type LoadMoreFn<TVariables extends Variables> = (
|
|
44
44
|
count: number,
|
|
45
45
|
options?: {
|
|
46
46
|
onComplete?: (Error | null) => void,
|
|
@@ -51,10 +51,10 @@ export type LoadMoreFn<TVariables: Variables> = (
|
|
|
51
51
|
export type UseLoadMoreFunctionArgs = {
|
|
52
52
|
direction: Direction,
|
|
53
53
|
fragmentNode: ReaderFragment,
|
|
54
|
-
fragmentRef:
|
|
54
|
+
fragmentRef: unknown,
|
|
55
55
|
fragmentIdentifier: string,
|
|
56
|
-
fragmentData:
|
|
57
|
-
connectionPathInFragmentData:
|
|
56
|
+
fragmentData: unknown,
|
|
57
|
+
connectionPathInFragmentData: ReadonlyArray<string | number>,
|
|
58
58
|
paginationRequest: ConcreteRequest,
|
|
59
59
|
paginationMetadata: ReaderPaginationMetadata,
|
|
60
60
|
componentDisplayName: string,
|
|
@@ -62,12 +62,13 @@ export type UseLoadMoreFunctionArgs = {
|
|
|
62
62
|
onReset: () => void,
|
|
63
63
|
};
|
|
64
64
|
|
|
65
|
-
hook useLoadMoreFunction<TVariables
|
|
65
|
+
hook useLoadMoreFunction<TVariables extends Variables>(
|
|
66
66
|
args: UseLoadMoreFunctionArgs,
|
|
67
67
|
): [LoadMoreFn<TVariables>, boolean, () => void] {
|
|
68
68
|
if (RelayFeatureFlags.ENABLE_ACTIVITY_COMPATIBILITY) {
|
|
69
69
|
// $FlowFixMe[react-rule-hook] - the condition is static
|
|
70
70
|
// $FlowFixMe[react-rule-hook-conditional]
|
|
71
|
+
// $FlowFixMe[incompatible-type]
|
|
71
72
|
return useLoadMoreFunction_EXPERIMENTAL(args);
|
|
72
73
|
}
|
|
73
74
|
// $FlowFixMe[react-rule-hook] - the condition is static
|
|
@@ -75,7 +76,7 @@ hook useLoadMoreFunction<TVariables: Variables>(
|
|
|
75
76
|
return useLoadMoreFunction_CURRENT(args);
|
|
76
77
|
}
|
|
77
78
|
|
|
78
|
-
hook useLoadMoreFunction_CURRENT<TVariables
|
|
79
|
+
hook useLoadMoreFunction_CURRENT<TVariables extends Variables>(
|
|
79
80
|
args: UseLoadMoreFunctionArgs,
|
|
80
81
|
): [LoadMoreFn<TVariables>, boolean, () => void] {
|
|
81
82
|
const {
|
|
@@ -38,7 +38,7 @@ const {
|
|
|
38
38
|
} = require('relay-runtime');
|
|
39
39
|
const warning = require('warning');
|
|
40
40
|
|
|
41
|
-
export type LoadMoreFn<TVariables
|
|
41
|
+
export type LoadMoreFn<TVariables extends Variables> = (
|
|
42
42
|
count: number,
|
|
43
43
|
options?: {
|
|
44
44
|
onComplete?: (Error | null) => void,
|
|
@@ -49,10 +49,10 @@ export type LoadMoreFn<TVariables: Variables> = (
|
|
|
49
49
|
export type UseLoadMoreFunctionArgs = {
|
|
50
50
|
direction: Direction,
|
|
51
51
|
fragmentNode: ReaderFragment,
|
|
52
|
-
fragmentRef:
|
|
52
|
+
fragmentRef: unknown,
|
|
53
53
|
fragmentIdentifier: string,
|
|
54
|
-
fragmentData:
|
|
55
|
-
connectionPathInFragmentData:
|
|
54
|
+
fragmentData: unknown,
|
|
55
|
+
connectionPathInFragmentData: ReadonlyArray<string | number>,
|
|
56
56
|
paginationRequest: ConcreteRequest,
|
|
57
57
|
paginationMetadata: ReaderPaginationMetadata,
|
|
58
58
|
componentDisplayName: string,
|
|
@@ -60,7 +60,7 @@ export type UseLoadMoreFunctionArgs = {
|
|
|
60
60
|
onReset: () => void,
|
|
61
61
|
};
|
|
62
62
|
|
|
63
|
-
hook useLoadMoreFunction_EXPERIMENTAL<TVariables
|
|
63
|
+
hook useLoadMoreFunction_EXPERIMENTAL<TVariables extends Variables>(
|
|
64
64
|
args: UseLoadMoreFunctionArgs,
|
|
65
65
|
): [
|
|
66
66
|
// Function to load more data
|
|
@@ -21,7 +21,7 @@ const {useState} = require('react');
|
|
|
21
21
|
* This is useful when a `variables` object is used as a value in a depencency
|
|
22
22
|
* array as it might often be constructed during render.
|
|
23
23
|
*/
|
|
24
|
-
hook useMemoVariables<TVariables
|
|
24
|
+
hook useMemoVariables<TVariables extends Variables | null>(
|
|
25
25
|
variables: TVariables,
|
|
26
26
|
): TVariables {
|
|
27
27
|
const [mirroredVariables, setMirroredVariables] = useState(variables);
|
|
@@ -24,14 +24,13 @@ import type {
|
|
|
24
24
|
Variables,
|
|
25
25
|
} from 'relay-runtime';
|
|
26
26
|
|
|
27
|
-
const useIsMountedRef = require('./useIsMountedRef');
|
|
28
27
|
const useRelayEnvironment = require('./useRelayEnvironment');
|
|
29
28
|
const React = require('react');
|
|
30
29
|
const {commitMutation: defaultCommitMutation} = require('relay-runtime');
|
|
31
30
|
|
|
32
31
|
const {useState, useEffect, useRef, useCallback} = React;
|
|
33
32
|
|
|
34
|
-
export type UseMutationConfig<TMutation
|
|
33
|
+
export type UseMutationConfig<TMutation extends MutationParameters> = {
|
|
35
34
|
configs?: Array<DeclarativeMutationConfig>,
|
|
36
35
|
onError?: ?(error: Error) => void,
|
|
37
36
|
onCompleted?: ?(
|
|
@@ -64,7 +63,7 @@ type UseMutationConfigInternal<TVariables, TData, TRawResponse> = {
|
|
|
64
63
|
variables: TVariables,
|
|
65
64
|
};
|
|
66
65
|
|
|
67
|
-
hook useMutation<TVariables
|
|
66
|
+
hook useMutation<TVariables extends Variables, TData, TRawResponse = {...}>(
|
|
68
67
|
mutation: Mutation<TVariables, TData, TRawResponse>,
|
|
69
68
|
commitMutationFn?: (
|
|
70
69
|
environment: IEnvironment,
|
|
@@ -75,7 +74,6 @@ hook useMutation<TVariables: Variables, TData, TRawResponse = {...}>(
|
|
|
75
74
|
boolean,
|
|
76
75
|
] {
|
|
77
76
|
const environment = useRelayEnvironment();
|
|
78
|
-
const isMountedRef = useIsMountedRef();
|
|
79
77
|
const environmentRef = useRef(environment);
|
|
80
78
|
const mutationRef = useRef(mutation);
|
|
81
79
|
const inFlightMutationsRef = useRef(new Set<Disposable>());
|
|
@@ -88,12 +86,10 @@ hook useMutation<TVariables: Variables, TData, TRawResponse = {...}>(
|
|
|
88
86
|
mutationRef.current === mutation
|
|
89
87
|
) {
|
|
90
88
|
inFlightMutationsRef.current.delete(disposable);
|
|
91
|
-
|
|
92
|
-
setMutationInFlight(inFlightMutationsRef.current.size > 0);
|
|
93
|
-
}
|
|
89
|
+
setMutationInFlight(inFlightMutationsRef.current.size > 0);
|
|
94
90
|
}
|
|
95
91
|
},
|
|
96
|
-
[environment,
|
|
92
|
+
[environment, mutation],
|
|
97
93
|
);
|
|
98
94
|
|
|
99
95
|
useEffect(() => {
|
|
@@ -102,19 +98,15 @@ hook useMutation<TVariables: Variables, TData, TRawResponse = {...}>(
|
|
|
102
98
|
mutationRef.current !== mutation
|
|
103
99
|
) {
|
|
104
100
|
inFlightMutationsRef.current = new Set();
|
|
105
|
-
|
|
106
|
-
setMutationInFlight(false);
|
|
107
|
-
}
|
|
101
|
+
setMutationInFlight(false);
|
|
108
102
|
environmentRef.current = environment;
|
|
109
103
|
mutationRef.current = mutation;
|
|
110
104
|
}
|
|
111
|
-
}, [environment,
|
|
105
|
+
}, [environment, mutation]);
|
|
112
106
|
|
|
113
107
|
const commit = useCallback(
|
|
114
108
|
(config: UseMutationConfigInternal<TVariables, TData, TRawResponse>) => {
|
|
115
|
-
|
|
116
|
-
setMutationInFlight(true);
|
|
117
|
-
}
|
|
109
|
+
setMutationInFlight(true);
|
|
118
110
|
const disposable: Disposable = commitMutationFn(environment, {
|
|
119
111
|
...config,
|
|
120
112
|
mutation,
|
|
@@ -137,7 +129,7 @@ hook useMutation<TVariables: Variables, TData, TRawResponse = {...}>(
|
|
|
137
129
|
inFlightMutationsRef.current.add(disposable);
|
|
138
130
|
return disposable;
|
|
139
131
|
},
|
|
140
|
-
[cleanup, commitMutationFn, environment,
|
|
132
|
+
[cleanup, commitMutationFn, environment, mutation],
|
|
141
133
|
);
|
|
142
134
|
|
|
143
135
|
return [commit, isMutationInFlight];
|
|
@@ -0,0 +1,68 @@
|
|
|
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 {Mutation, Variables} from 'relay-runtime';
|
|
15
|
+
|
|
16
|
+
const useRelayEnvironment = require('./useRelayEnvironment');
|
|
17
|
+
const React = require('react');
|
|
18
|
+
const {commitMutation} = require('relay-runtime');
|
|
19
|
+
|
|
20
|
+
const {useCallback} = React;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* A variant of useMutation that returns an action function suitable for use
|
|
24
|
+
* with React's action prop pattern. The returned action is an async function
|
|
25
|
+
* that can be passed to `startTransition` or used as an action prop, enabling
|
|
26
|
+
* optimistic UI updates via `useOptimistic`.
|
|
27
|
+
* https://react.dev/reference/react/useTransition#starttransition
|
|
28
|
+
*
|
|
29
|
+
* Usage:
|
|
30
|
+
* const commitAction = useMutationAction_EXPERIMENTAL(mutation);
|
|
31
|
+
*
|
|
32
|
+
* // In a startTransition or action prop:
|
|
33
|
+
* startTransition(async () => {
|
|
34
|
+
* setOptimisticValue(newValue);
|
|
35
|
+
* await commitAction({input: newValue});
|
|
36
|
+
* });
|
|
37
|
+
*/
|
|
38
|
+
hook useMutationAction_EXPERIMENTAL<
|
|
39
|
+
TVariables extends Variables,
|
|
40
|
+
TData,
|
|
41
|
+
TRawResponse = {...},
|
|
42
|
+
>(
|
|
43
|
+
mutation: Mutation<TVariables, TData, TRawResponse>,
|
|
44
|
+
): (variables: TVariables) => Promise<TData> {
|
|
45
|
+
const environment = useRelayEnvironment();
|
|
46
|
+
|
|
47
|
+
const commitAction = useCallback(
|
|
48
|
+
(variables: TVariables): Promise<TData> => {
|
|
49
|
+
return new Promise((resolve, reject) => {
|
|
50
|
+
commitMutation(environment, {
|
|
51
|
+
mutation,
|
|
52
|
+
variables,
|
|
53
|
+
onCompleted: (response: TData) => {
|
|
54
|
+
resolve(response);
|
|
55
|
+
},
|
|
56
|
+
onError: (error: Error) => {
|
|
57
|
+
reject(error);
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
},
|
|
62
|
+
[environment, mutation],
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
return commitAction;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
module.exports = useMutationAction_EXPERIMENTAL;
|
|
@@ -32,11 +32,14 @@ const {
|
|
|
32
32
|
getPaginationMetadata,
|
|
33
33
|
} = require('relay-runtime');
|
|
34
34
|
|
|
35
|
-
type RefetchVariables<
|
|
35
|
+
type RefetchVariables<
|
|
36
|
+
TVariables,
|
|
37
|
+
TKey extends ?{+$fragmentSpreads: unknown, ...},
|
|
38
|
+
> =
|
|
36
39
|
// NOTE: This type ensures that the type of the returned variables is either:
|
|
37
40
|
// - nullable if the provided ref type is nullable
|
|
38
41
|
// - non-nullable if the provided ref type is non-nullable
|
|
39
|
-
[+key: TKey] extends [+key: {+$fragmentSpreads:
|
|
42
|
+
[+key: TKey] extends [+key: {+$fragmentSpreads: unknown, ...}]
|
|
40
43
|
? Partial<TVariables>
|
|
41
44
|
: TVariables;
|
|
42
45
|
|
|
@@ -54,7 +57,7 @@ export type ReturnType<TVariables, TData, TKey> = {
|
|
|
54
57
|
// NOTE: This type ensures that the type of the returned data is either:
|
|
55
58
|
// - nullable if the provided ref type is nullable
|
|
56
59
|
// - non-nullable if the provided ref type is non-nullable
|
|
57
|
-
data: [+key: TKey] extends [+key: {+$fragmentSpreads:
|
|
60
|
+
data: [+key: TKey] extends [+key: {+$fragmentSpreads: unknown, ...}]
|
|
58
61
|
? TData
|
|
59
62
|
: ?TData,
|
|
60
63
|
loadNext: LoadMoreFn<TVariables>,
|
|
@@ -70,20 +73,20 @@ export type ReturnType<TVariables, TData, TKey> = {
|
|
|
70
73
|
// a separate hooks implementation in ./HooksImplementation -- it can
|
|
71
74
|
// be removed after we stop doing that.
|
|
72
75
|
export type UsePaginationFragmentType = <
|
|
73
|
-
TFragmentType
|
|
74
|
-
TVariables
|
|
76
|
+
TFragmentType extends FragmentType,
|
|
77
|
+
TVariables extends Variables,
|
|
75
78
|
TData,
|
|
76
|
-
TKey
|
|
79
|
+
TKey extends ?{+$fragmentSpreads: TFragmentType, ...},
|
|
77
80
|
>(
|
|
78
81
|
fragmentInput: RefetchableFragment<TFragmentType, TData, TVariables>,
|
|
79
82
|
parentFragmentRef: TKey,
|
|
80
83
|
) => ReturnType<TVariables, TData, TKey>;
|
|
81
84
|
|
|
82
85
|
hook usePaginationFragment<
|
|
83
|
-
TFragmentType
|
|
84
|
-
TVariables
|
|
86
|
+
TFragmentType extends FragmentType,
|
|
87
|
+
TVariables extends Variables,
|
|
85
88
|
TData,
|
|
86
|
-
TKey
|
|
89
|
+
TKey extends ?{+$fragmentSpreads: TFragmentType, ...},
|
|
87
90
|
>(
|
|
88
91
|
fragmentInput: RefetchableFragment<TFragmentType, TData, TVariables>,
|
|
89
92
|
parentFragmentRef: TKey,
|
|
@@ -155,7 +158,7 @@ hook usePaginationFragment<
|
|
|
155
158
|
});
|
|
156
159
|
}
|
|
157
160
|
return {
|
|
158
|
-
// $FlowFixMe[incompatible-
|
|
161
|
+
// $FlowFixMe[incompatible-type]
|
|
159
162
|
data: fragmentData,
|
|
160
163
|
loadNext,
|
|
161
164
|
loadPrevious,
|
|
@@ -163,11 +166,12 @@ hook usePaginationFragment<
|
|
|
163
166
|
hasPrevious,
|
|
164
167
|
isLoadingNext,
|
|
165
168
|
isLoadingPrevious,
|
|
169
|
+
// $FlowFixMe[incompatible-type]
|
|
166
170
|
refetch: refetchPagination,
|
|
167
171
|
};
|
|
168
172
|
}
|
|
169
173
|
|
|
170
|
-
hook useLoadMore<TVariables
|
|
174
|
+
hook useLoadMore<TVariables extends Variables>(
|
|
171
175
|
args: Omit<UseLoadMoreFunctionArgs, 'observer' | 'onReset'>,
|
|
172
176
|
): [LoadMoreFn<TVariables>, boolean, boolean, () => void] {
|
|
173
177
|
const environment = useRelayEnvironment();
|
|
@@ -43,7 +43,7 @@ const {
|
|
|
43
43
|
getValueAtPath,
|
|
44
44
|
} = require('relay-runtime');
|
|
45
45
|
|
|
46
|
-
type LoadMoreFn<TVariables
|
|
46
|
+
type LoadMoreFn<TVariables extends Variables> = (
|
|
47
47
|
count: number,
|
|
48
48
|
options?: {
|
|
49
49
|
onComplete?: (Error | null) => void,
|
|
@@ -55,7 +55,7 @@ export type ReturnType<TVariables, TData, TEdgeData, TKey> = {
|
|
|
55
55
|
// NOTE: This type ensures that the type of the returned data is either:
|
|
56
56
|
// - nullable if the provided ref type is nullable
|
|
57
57
|
// - non-nullable if the provided ref type is non-nullable
|
|
58
|
-
data: [+key: TKey] extends [+key: {+$fragmentSpreads:
|
|
58
|
+
data: [+key: TKey] extends [+key: {+$fragmentSpreads: unknown, ...}]
|
|
59
59
|
? TData
|
|
60
60
|
: ?TData,
|
|
61
61
|
loadNext: LoadMoreFn<TVariables>,
|
|
@@ -72,18 +72,18 @@ type LoadMoreOptions<TVariables> = {
|
|
|
72
72
|
|
|
73
73
|
export type GetExtraVariablesFn<TEdgeData, TData, TVariables, TKey> = ({
|
|
74
74
|
hasNext: boolean,
|
|
75
|
-
data: [+key: TKey] extends [+key: {+$fragmentSpreads:
|
|
75
|
+
data: [+key: TKey] extends [+key: {+$fragmentSpreads: unknown, ...}]
|
|
76
76
|
? TData
|
|
77
77
|
: ?TData,
|
|
78
78
|
getServerEdges: () => TEdgeData,
|
|
79
79
|
}) => Partial<TVariables>;
|
|
80
80
|
|
|
81
81
|
hook usePrefetchableForwardPaginationFragment<
|
|
82
|
-
TFragmentType
|
|
83
|
-
TVariables
|
|
82
|
+
TFragmentType extends FragmentType,
|
|
83
|
+
TVariables extends Variables,
|
|
84
84
|
TData,
|
|
85
85
|
TEdgeData,
|
|
86
|
-
TKey
|
|
86
|
+
TKey extends ?{+$fragmentSpreads: TFragmentType, ...},
|
|
87
87
|
>(
|
|
88
88
|
fragmentInput: PrefetchableRefetchableFragment<
|
|
89
89
|
TFragmentType,
|
|
@@ -257,26 +257,26 @@ hook usePrefetchableForwardPaginationFragment<
|
|
|
257
257
|
onComplete: prefetchingOnComplete,
|
|
258
258
|
UNSTABLE_extraVariables:
|
|
259
259
|
typeof prefetchingUNSTABLE_extraVariables === 'function'
|
|
260
|
-
? // $FlowFixMe[incompatible-
|
|
260
|
+
? // $FlowFixMe[incompatible-type]
|
|
261
261
|
prefetchingUNSTABLE_extraVariables({
|
|
262
262
|
hasNext,
|
|
263
|
-
// $FlowFixMe[incompatible-
|
|
263
|
+
// $FlowFixMe[incompatible-type]
|
|
264
264
|
data: fragmentData,
|
|
265
265
|
getServerEdges: () => {
|
|
266
266
|
const selector = getSelector(
|
|
267
|
-
// $FlowFixMe[incompatible-
|
|
267
|
+
// $FlowFixMe[incompatible-type]
|
|
268
268
|
edgesFragment,
|
|
269
269
|
edgeKeys,
|
|
270
270
|
);
|
|
271
271
|
if (selector == null) {
|
|
272
|
-
// $FlowFixMe[incompatible-
|
|
272
|
+
// $FlowFixMe[incompatible-type]
|
|
273
273
|
return [];
|
|
274
274
|
}
|
|
275
275
|
invariant(
|
|
276
276
|
selector.kind === 'PluralReaderSelector',
|
|
277
277
|
'Expected a plural selector',
|
|
278
278
|
);
|
|
279
|
-
// $FlowFixMe[incompatible-
|
|
279
|
+
// $FlowFixMe[incompatible-type]
|
|
280
280
|
return selector.selectors.map(
|
|
281
281
|
sel => environment.lookup(sel).data,
|
|
282
282
|
);
|
|
@@ -332,22 +332,22 @@ hook usePrefetchableForwardPaginationFragment<
|
|
|
332
332
|
onComplete,
|
|
333
333
|
UNSTABLE_extraVariables:
|
|
334
334
|
typeof prefetchingUNSTABLE_extraVariables === 'function'
|
|
335
|
-
? // $FlowFixMe[incompatible-
|
|
335
|
+
? // $FlowFixMe[incompatible-type]
|
|
336
336
|
prefetchingUNSTABLE_extraVariables({
|
|
337
337
|
hasNext,
|
|
338
|
-
// $FlowFixMe[incompatible-
|
|
338
|
+
// $FlowFixMe[incompatible-type]
|
|
339
339
|
data: fragmentData,
|
|
340
340
|
getServerEdges: () => {
|
|
341
341
|
const selector = getSelector(edgesFragment, edgeKeys);
|
|
342
342
|
if (selector == null) {
|
|
343
|
-
// $FlowFixMe[incompatible-
|
|
343
|
+
// $FlowFixMe[incompatible-type]
|
|
344
344
|
return [];
|
|
345
345
|
}
|
|
346
346
|
invariant(
|
|
347
347
|
selector.kind === 'PluralReaderSelector',
|
|
348
348
|
'Expected a plural selector',
|
|
349
349
|
);
|
|
350
|
-
// $FlowFixMe[incompatible-
|
|
350
|
+
// $FlowFixMe[incompatible-type]
|
|
351
351
|
return selector.selectors.map(
|
|
352
352
|
sel => environment.lookup(sel).data,
|
|
353
353
|
);
|
|
@@ -375,12 +375,12 @@ hook usePrefetchableForwardPaginationFragment<
|
|
|
375
375
|
|
|
376
376
|
const realNumInUse = Math.min(numInUse, sourceSize);
|
|
377
377
|
|
|
378
|
-
const derivedEdgeKeys:
|
|
378
|
+
const derivedEdgeKeys: ReadonlyArray<unknown> = useMemo(
|
|
379
379
|
() => edgeKeys?.slice(0, realNumInUse) ?? [],
|
|
380
380
|
[edgeKeys, realNumInUse],
|
|
381
381
|
);
|
|
382
382
|
|
|
383
|
-
// $FlowExpectedError[incompatible-
|
|
383
|
+
// $FlowExpectedError[incompatible-type] - we know derivedEdgeKeys are the correct keys
|
|
384
384
|
const edges: TEdgeData = useFragment(edgesFragment, derivedEdgeKeys);
|
|
385
385
|
|
|
386
386
|
const refetchPagination = useCallback(
|
|
@@ -422,13 +422,14 @@ hook usePrefetchableForwardPaginationFragment<
|
|
|
422
422
|
|
|
423
423
|
return {
|
|
424
424
|
edges,
|
|
425
|
-
// $FlowFixMe[incompatible-
|
|
425
|
+
// $FlowFixMe[incompatible-type]
|
|
426
426
|
data: fragmentData,
|
|
427
427
|
loadNext: showMore,
|
|
428
428
|
hasNext: hasNext || sourceSize > numInUse,
|
|
429
429
|
// Only reflect `isLoadingMore` if the product depends on it, do not refelect
|
|
430
430
|
// `isLoaindgMore` state if it is for fufilling the buffer
|
|
431
431
|
isLoadingNext: isLoadingMore && numInUse > sourceSize,
|
|
432
|
+
// $FlowFixMe[incompatible-type]
|
|
432
433
|
refetch: refetchPagination,
|
|
433
434
|
};
|
|
434
435
|
}
|