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.
Files changed (129) hide show
  1. package/ReactRelayContext.js +1 -1
  2. package/ReactRelayContext.js.flow +2 -2
  3. package/ReactRelayFragmentContainer.js.flow +9 -10
  4. package/ReactRelayLocalQueryRenderer.js.flow +11 -3
  5. package/ReactRelayLoggingContext.js.flow +3 -3
  6. package/ReactRelayPaginationContainer.js.flow +32 -25
  7. package/ReactRelayQueryFetcher.js.flow +1 -1
  8. package/ReactRelayQueryRenderer.js.flow +2 -2
  9. package/ReactRelayQueryRendererContext.js.flow +2 -2
  10. package/ReactRelayRefetchContainer.js.flow +18 -15
  11. package/ReactRelayTestMocker.js.flow +10 -10
  12. package/ReactRelayTypes.js.flow +18 -20
  13. package/RelayContext.js.flow +3 -3
  14. package/__flowtests__/ReactRelayFragmentContainer-flowtest.js.flow +11 -11
  15. package/__flowtests__/ReactRelayPaginationContainer-flowtest.js.flow +5 -5
  16. package/__flowtests__/ReactRelayRefetchContainer-flowtest.js.flow +5 -5
  17. package/__flowtests__/RelayModern-flowtest.js.flow +24 -27
  18. package/__flowtests__/RelayModernFlowtest_users.graphql.js.flow +1 -1
  19. package/__flowtests__/__generated__/ReactRelayFragmentContainerFlowtest_viewer.graphql.js.flow +3 -4
  20. package/__flowtests__/__generated__/ReactRelayFragmentContainerFlowtest_viewer2.graphql.js.flow +3 -4
  21. package/__flowtests__/__generated__/ReactRelayPaginationContainerFlowtestQuery.graphql.js.flow +9 -10
  22. package/__flowtests__/__generated__/ReactRelayPaginationContainerFlowtest_viewer.graphql.js.flow +4 -5
  23. package/__flowtests__/__generated__/ReactRelayRefetchContainerFlowtestQuery.graphql.js.flow +9 -10
  24. package/__flowtests__/__generated__/ReactRelayRefetchContainerFlowtest_viewer.graphql.js.flow +4 -5
  25. package/__flowtests__/__generated__/RelayModernFlowtest_badref.graphql.js.flow +3 -4
  26. package/__flowtests__/__generated__/RelayModernFlowtest_notref.graphql.js.flow +3 -4
  27. package/__flowtests__/__generated__/RelayModernFlowtest_user.graphql.js.flow +3 -4
  28. package/__flowtests__/__generated__/RelayModernFlowtest_users.graphql.js.flow +5 -6
  29. package/buildReactRelayContainer.js.flow +4 -4
  30. package/getRootVariablesForFragments.js.flow +3 -3
  31. package/hooks.js +1 -1
  32. package/hooks.js.flow +23 -8
  33. package/index.js +1 -1
  34. package/index.js.flow +40 -14
  35. package/isRelayEnvironment.js.flow +1 -1
  36. package/jest-react/internalAct.js.flow +1 -1
  37. package/legacy.js +1 -1
  38. package/legacy.js.flow +32 -13
  39. package/lib/ReactRelayFragmentContainer.js +1 -1
  40. package/lib/ReactRelayPaginationContainer.js +8 -8
  41. package/lib/ReactRelayRefetchContainer.js +8 -8
  42. package/lib/ReactRelayTestMocker.js +5 -5
  43. package/lib/hooks.js +18 -8
  44. package/lib/index.js +30 -14
  45. package/lib/legacy.js +26 -13
  46. package/lib/relay-hooks/legacy/useBlockingPaginationFragment.js +5 -5
  47. package/lib/relay-hooks/legacy/useRefetchableFragmentNode.js +34 -34
  48. package/lib/relay-hooks/loadEntryPoint.js +2 -2
  49. package/lib/relay-hooks/loadQuery.js +14 -14
  50. package/lib/relay-hooks/preloadQuery_DEPRECATED.js +10 -10
  51. package/lib/relay-hooks/readFragmentInternal.js +6 -6
  52. package/lib/relay-hooks/rsc/serverFetchQuery.js +20 -0
  53. package/lib/relay-hooks/rsc/serverPreloadQuery.js +31 -0
  54. package/lib/relay-hooks/rsc/serverReadFragment.js +15 -0
  55. package/lib/relay-hooks/rsc/useQueryFromServer.js +62 -0
  56. package/lib/relay-hooks/useFragmentInternal_CURRENT.js +49 -25
  57. package/lib/relay-hooks/useFragmentInternal_EXPERIMENTAL.js +81 -44
  58. package/lib/relay-hooks/useLazyLoadQueryNode.js +32 -19
  59. package/lib/relay-hooks/useMutation.js +6 -14
  60. package/lib/relay-hooks/useMutationAction_EXPERIMENTAL.js +26 -0
  61. package/lib/relay-hooks/usePreloadedQuery.js +52 -47
  62. package/lib/relay-hooks/useQueryLoader.js +2 -2
  63. package/lib/relay-hooks/useQueryLoader_EXPERIMENTAL.js +2 -2
  64. package/lib/relay-hooks/useRefetchableFragmentInternal.js +31 -31
  65. package/lib/rsc-client_EXPERIMENTAL.js +7 -0
  66. package/lib/rsc_EXPERIMENTAL.js +43 -0
  67. package/multi-actor/ActorChange.js.flow +1 -1
  68. package/package.json +3 -2
  69. package/relay-hooks/EntryPointContainer.react.js.flow +6 -6
  70. package/relay-hooks/EntryPointTypes.flow.js.flow +61 -67
  71. package/relay-hooks/LazyLoadEntryPointContainer_DEPRECATED.react.js.flow +23 -21
  72. package/relay-hooks/MatchContainer.js.flow +12 -6
  73. package/relay-hooks/NestedRelayEntryPointBuilderUtils.js.flow +3 -9
  74. package/relay-hooks/QueryResource.js.flow +6 -6
  75. package/relay-hooks/RelayEnvironmentProvider.js.flow +2 -2
  76. package/relay-hooks/__flowtests__/EntryPointTypes/EntryPointElementConfig-flowtest.js.flow +6 -6
  77. package/relay-hooks/__flowtests__/EntryPointTypes/ExtractQueryTypes-flowtest.js.flow +48 -1
  78. package/relay-hooks/__flowtests__/EntryPointTypes/NestedEntrypoints-flowtest.js.flow +9 -9
  79. package/relay-hooks/__flowtests__/__generated__/useFragmentFlowtest_user.graphql.js.flow +3 -4
  80. package/relay-hooks/__flowtests__/__generated__/useFragmentFlowtest_users.graphql.js.flow +5 -6
  81. package/relay-hooks/__flowtests__/useBlockingPaginationFragment-flowtest.js.flow +27 -32
  82. package/relay-hooks/__flowtests__/useFragment-flowtest.js.flow +25 -25
  83. package/relay-hooks/__flowtests__/usePaginationFragment-flowtest.js.flow +26 -32
  84. package/relay-hooks/__flowtests__/useRefetchableFragment-flowtest.js.flow +23 -30
  85. package/relay-hooks/__flowtests__/utils.js.flow +4 -4
  86. package/relay-hooks/getConnectionState.js.flow +4 -4
  87. package/relay-hooks/legacy/FragmentResource.js.flow +13 -13
  88. package/relay-hooks/legacy/useBlockingPaginationFragment.js.flow +24 -25
  89. package/relay-hooks/legacy/useFragmentNode.js.flow +4 -4
  90. package/relay-hooks/legacy/useRefetchableFragmentNode.js.flow +79 -81
  91. package/relay-hooks/loadEntryPoint.js.flow +16 -14
  92. package/relay-hooks/loadQuery.js.flow +18 -18
  93. package/relay-hooks/preloadQuery_DEPRECATED.js.flow +16 -13
  94. package/relay-hooks/prepareEntryPoint_DEPRECATED.js.flow +7 -7
  95. package/relay-hooks/readFragmentInternal.js.flow +9 -9
  96. package/relay-hooks/rsc/serverFetchQuery.js.flow +31 -0
  97. package/relay-hooks/rsc/serverPreloadQuery.js.flow +69 -0
  98. package/relay-hooks/rsc/serverReadFragment.js.flow +33 -0
  99. package/relay-hooks/rsc/useQueryFromServer.js.flow +135 -0
  100. package/relay-hooks/useClientQuery.js.flow +2 -2
  101. package/relay-hooks/useEntryPointLoader.js.flow +11 -11
  102. package/relay-hooks/useFragment.js.flow +7 -7
  103. package/relay-hooks/useFragmentInternal.js.flow +1 -1
  104. package/relay-hooks/useFragmentInternal_CURRENT.js.flow +54 -22
  105. package/relay-hooks/useFragmentInternal_EXPERIMENTAL.js.flow +95 -46
  106. package/relay-hooks/useIsOperationNodeActive.js.flow +1 -1
  107. package/relay-hooks/useIsParentQueryActive.js.flow +1 -1
  108. package/relay-hooks/useLazyLoadQuery.js.flow +10 -3
  109. package/relay-hooks/useLazyLoadQueryNode.js.flow +67 -28
  110. package/relay-hooks/useLoadMoreFunction.js.flow +7 -6
  111. package/relay-hooks/useLoadMoreFunction_EXPERIMENTAL.js.flow +5 -5
  112. package/relay-hooks/useMemoVariables.js.flow +1 -1
  113. package/relay-hooks/useMutation.js.flow +8 -16
  114. package/relay-hooks/useMutationAction_EXPERIMENTAL.js.flow +68 -0
  115. package/relay-hooks/usePaginationFragment.js.flow +15 -11
  116. package/relay-hooks/usePrefetchableForwardPaginationFragment.js.flow +19 -18
  117. package/relay-hooks/usePrefetchableForwardPaginationFragment_EXPERIMENTAL.js.flow +19 -18
  118. package/relay-hooks/usePreloadedQuery.js.flow +119 -85
  119. package/relay-hooks/useQueryLoader.js.flow +27 -23
  120. package/relay-hooks/useQueryLoader_EXPERIMENTAL.js.flow +10 -10
  121. package/relay-hooks/useRefetchableFragment.js.flow +16 -11
  122. package/relay-hooks/useRefetchableFragmentInternal.js.flow +77 -79
  123. package/relay-hooks/useRelayLoggingContext.js.flow +1 -1
  124. package/relay-hooks/useSubscribeToInvalidationState.js.flow +1 -1
  125. package/relay-hooks/useSubscription.js.flow +1 -1
  126. package/rsc-client_EXPERIMENTAL.js +10 -0
  127. package/rsc-client_EXPERIMENTAL.js.flow +23 -0
  128. package/rsc_EXPERIMENTAL.js +10 -0
  129. 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
- hook useLazyLoadQueryNode<TQuery: OperationType>({
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
- }): TQuery['response'] {
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
- const preparedQueryResult = profilerContext.wrapPrepareQueryResource(() => {
66
- return QueryResource.prepareWithIdentifier(
67
- cacheIdentifier,
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
- {start: startFetch, complete: completeFetch, error: completeFetch},
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
- return data;
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: Variables> = (
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: mixed,
54
+ fragmentRef: unknown,
55
55
  fragmentIdentifier: string,
56
- fragmentData: mixed,
57
- connectionPathInFragmentData: $ReadOnlyArray<string | number>,
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: Variables>(
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: Variables>(
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: Variables> = (
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: mixed,
52
+ fragmentRef: unknown,
53
53
  fragmentIdentifier: string,
54
- fragmentData: mixed,
55
- connectionPathInFragmentData: $ReadOnlyArray<string | number>,
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: Variables>(
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: Variables | null>(
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: MutationParameters> = {
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: Variables, TData, TRawResponse = {...}>(
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
- if (isMountedRef.current) {
92
- setMutationInFlight(inFlightMutationsRef.current.size > 0);
93
- }
89
+ setMutationInFlight(inFlightMutationsRef.current.size > 0);
94
90
  }
95
91
  },
96
- [environment, isMountedRef, mutation],
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
- if (isMountedRef.current) {
106
- setMutationInFlight(false);
107
- }
101
+ setMutationInFlight(false);
108
102
  environmentRef.current = environment;
109
103
  mutationRef.current = mutation;
110
104
  }
111
- }, [environment, isMountedRef, mutation]);
105
+ }, [environment, mutation]);
112
106
 
113
107
  const commit = useCallback(
114
108
  (config: UseMutationConfigInternal<TVariables, TData, TRawResponse>) => {
115
- if (isMountedRef.current) {
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, isMountedRef, mutation],
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<TVariables, TKey: ?{+$fragmentSpreads: mixed, ...}> =
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: mixed, ...}]
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: mixed, ...}]
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: FragmentType,
74
- TVariables: Variables,
76
+ TFragmentType extends FragmentType,
77
+ TVariables extends Variables,
75
78
  TData,
76
- TKey: ?{+$fragmentSpreads: TFragmentType, ...},
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: FragmentType,
84
- TVariables: Variables,
86
+ TFragmentType extends FragmentType,
87
+ TVariables extends Variables,
85
88
  TData,
86
- TKey: ?{+$fragmentSpreads: TFragmentType, ...},
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-return]
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: Variables>(
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: Variables> = (
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: mixed, ...}]
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: mixed, ...}]
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: FragmentType,
83
- TVariables: Variables,
82
+ TFragmentType extends FragmentType,
83
+ TVariables extends Variables,
84
84
  TData,
85
85
  TEdgeData,
86
- TKey: ?{+$fragmentSpreads: TFragmentType, ...},
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-call]
260
+ ? // $FlowFixMe[incompatible-type]
261
261
  prefetchingUNSTABLE_extraVariables({
262
262
  hasNext,
263
- // $FlowFixMe[incompatible-call]
263
+ // $FlowFixMe[incompatible-type]
264
264
  data: fragmentData,
265
265
  getServerEdges: () => {
266
266
  const selector = getSelector(
267
- // $FlowFixMe[incompatible-call]
267
+ // $FlowFixMe[incompatible-type]
268
268
  edgesFragment,
269
269
  edgeKeys,
270
270
  );
271
271
  if (selector == null) {
272
- // $FlowFixMe[incompatible-call]
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-call]
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-call]
335
+ ? // $FlowFixMe[incompatible-type]
336
336
  prefetchingUNSTABLE_extraVariables({
337
337
  hasNext,
338
- // $FlowFixMe[incompatible-call]
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-call]
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-call]
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: $ReadOnlyArray<mixed> = useMemo(
378
+ const derivedEdgeKeys: ReadonlyArray<unknown> = useMemo(
379
379
  () => edgeKeys?.slice(0, realNumInUse) ?? [],
380
380
  [edgeKeys, realNumInUse],
381
381
  );
382
382
 
383
- // $FlowExpectedError[incompatible-call] - we know derivedEdgeKeys are the correct keys
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-return]
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
  }