react-relay 15.0.0 → 16.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (126) hide show
  1. package/ReactRelayContext.js +1 -1
  2. package/ReactRelayQueryFetcher.js.flow +1 -5
  3. package/ReactRelayQueryRenderer.js.flow +9 -36
  4. package/ReactRelayTypes.js.flow +1 -0
  5. package/buildReactRelayContainer.js.flow +3 -1
  6. package/hooks.js +1 -1
  7. package/index.js +1 -1
  8. package/legacy.js +1 -1
  9. package/lib/ReactRelayContainerUtils.js +0 -11
  10. package/lib/ReactRelayContext.js +0 -11
  11. package/lib/ReactRelayFragmentContainer.js +6 -78
  12. package/lib/ReactRelayFragmentMockRenderer.js +0 -11
  13. package/lib/ReactRelayLocalQueryRenderer.js +0 -17
  14. package/lib/ReactRelayPaginationContainer.js +5 -208
  15. package/lib/ReactRelayQueryFetcher.js +2 -51
  16. package/lib/ReactRelayQueryRenderer.js +6 -94
  17. package/lib/ReactRelayQueryRendererContext.js +0 -11
  18. package/lib/ReactRelayRefetchContainer.js +5 -91
  19. package/lib/ReactRelayTestMocker.js +9 -85
  20. package/lib/ReactRelayTypes.js +0 -11
  21. package/lib/RelayContext.js +0 -21
  22. package/lib/assertFragmentMap.js +0 -15
  23. package/lib/buildReactRelayContainer.js +0 -19
  24. package/lib/getRootVariablesForFragments.js +0 -14
  25. package/lib/hooks.js +0 -15
  26. package/lib/index.js +0 -17
  27. package/lib/isRelayEnvironment.js +1 -18
  28. package/lib/jest-react/enqueueTask.js +0 -20
  29. package/lib/jest-react/internalAct.js +0 -38
  30. package/lib/legacy.js +0 -15
  31. package/lib/multi-actor/ActorChange.js +0 -11
  32. package/lib/multi-actor/index.js +0 -11
  33. package/lib/multi-actor/useRelayActorEnvironment.js +0 -11
  34. package/lib/relay-hooks/EntryPointContainer.react.js +0 -11
  35. package/lib/relay-hooks/EntryPointTypes.flow.js +1 -14
  36. package/lib/relay-hooks/FragmentResource.js +76 -132
  37. package/lib/relay-hooks/HooksImplementation.js +1 -12
  38. package/lib/relay-hooks/InternalLogger.js +0 -11
  39. package/lib/relay-hooks/LRUCache.js +0 -22
  40. package/lib/relay-hooks/LazyLoadEntryPointContainer_DEPRECATED.react.js +0 -18
  41. package/lib/relay-hooks/MatchContainer.js +0 -94
  42. package/lib/relay-hooks/NestedRelayEntryPointBuilderUtils.js +9 -0
  43. package/lib/relay-hooks/ProfilerContext.js +0 -15
  44. package/lib/relay-hooks/QueryResource.js +2 -68
  45. package/lib/relay-hooks/RelayEnvironmentProvider.js +0 -11
  46. package/lib/relay-hooks/SuspenseResource.js +0 -34
  47. package/lib/relay-hooks/{react-cache/readFragmentInternal_REACT_CACHE.js → experimental/readFragmentInternal_EXPERIMENTAL.js} +5 -29
  48. package/lib/relay-hooks/{react-cache/useFragmentInternal_REACT_CACHE.js → experimental/useFragmentInternal_EXPERIMENTAL.js} +35 -100
  49. package/lib/relay-hooks/{react-cache/useFragment_REACT_CACHE.js → experimental/useFragment_EXPERIMENTAL.js} +1 -16
  50. package/lib/relay-hooks/{react-cache/usePaginationFragment_REACT_CACHE.js → experimental/usePaginationFragment_EXPERIMENTAL.js} +2 -24
  51. package/lib/relay-hooks/{react-cache/useRefetchableFragmentInternal_REACT_CACHE.js → experimental/useRefetchableFragmentInternal_EXPERIMENTAL.js} +14 -98
  52. package/lib/relay-hooks/{react-cache/useRefetchableFragment_REACT_CACHE.js → experimental/useRefetchableFragment_EXPERIMENTAL.js} +1 -15
  53. package/lib/relay-hooks/loadEntryPoint.js +1 -24
  54. package/lib/relay-hooks/loadQuery.js +2 -106
  55. package/lib/relay-hooks/preloadQuery_DEPRECATED.js +2 -27
  56. package/lib/relay-hooks/prepareEntryPoint_DEPRECATED.js +0 -13
  57. package/lib/relay-hooks/useBlockingPaginationFragment.js +0 -42
  58. package/lib/relay-hooks/useClientQuery.js +0 -18
  59. package/lib/relay-hooks/useEntryPointLoader.js +0 -69
  60. package/lib/relay-hooks/useFetchTrackingRef.js +0 -26
  61. package/lib/relay-hooks/useFragment.js +0 -17
  62. package/lib/relay-hooks/useFragmentNode.js +2 -32
  63. package/lib/relay-hooks/useIsMountedRef.js +0 -11
  64. package/lib/relay-hooks/useIsOperationNodeActive.js +0 -11
  65. package/lib/relay-hooks/useIsParentQueryActive.js +0 -11
  66. package/lib/relay-hooks/useLazyLoadQuery.js +0 -18
  67. package/lib/relay-hooks/useLazyLoadQueryNode.js +12 -37
  68. package/lib/relay-hooks/useLoadMoreFunction.js +9 -34
  69. package/lib/relay-hooks/useMemoOperationDescriptor.js +0 -11
  70. package/lib/relay-hooks/useMemoVariables.js +0 -17
  71. package/lib/relay-hooks/useMutation.js +0 -11
  72. package/lib/relay-hooks/usePaginationFragment.js +1 -26
  73. package/lib/relay-hooks/usePreloadedQuery.js +0 -27
  74. package/lib/relay-hooks/useQueryLoader.js +0 -74
  75. package/lib/relay-hooks/useRefetchableFragment.js +0 -16
  76. package/lib/relay-hooks/useRefetchableFragmentNode.js +14 -97
  77. package/lib/relay-hooks/useRelayEnvironment.js +0 -11
  78. package/lib/relay-hooks/useStaticFragmentNodeWarning.js +0 -15
  79. package/lib/relay-hooks/useSubscribeToInvalidationState.js +0 -25
  80. package/lib/relay-hooks/useSubscription.js +0 -15
  81. package/lib/relay-hooks/useUnsafeRef_DEPRECATED.js +0 -17
  82. package/package.json +2 -2
  83. package/react-relay-hooks.js +2 -2
  84. package/react-relay-hooks.min.js +2 -2
  85. package/react-relay-legacy.js +2 -2
  86. package/react-relay-legacy.min.js +2 -2
  87. package/react-relay.js +2 -2
  88. package/react-relay.min.js +2 -2
  89. package/relay-hooks/EntryPointContainer.react.js.flow +5 -0
  90. package/relay-hooks/EntryPointTypes.flow.js.flow +34 -35
  91. package/relay-hooks/FragmentResource.js.flow +114 -26
  92. package/relay-hooks/HooksImplementation.js.flow +3 -1
  93. package/relay-hooks/LazyLoadEntryPointContainer_DEPRECATED.react.js.flow +4 -2
  94. package/relay-hooks/NestedRelayEntryPointBuilderUtils.js.flow +51 -0
  95. package/relay-hooks/__flowtests__/EntryPointTypes/NestedEntrypoints-flowtest.js.flow +7 -5
  96. package/relay-hooks/__flowtests__/useBlockingPaginationFragment-flowtest.js.flow +5 -0
  97. package/relay-hooks/__flowtests__/usePaginationFragment-flowtest.js.flow +5 -0
  98. package/relay-hooks/__flowtests__/useRefetchableFragment-flowtest.js.flow +2 -0
  99. package/relay-hooks/{react-cache/readFragmentInternal_REACT_CACHE.js.flow → experimental/readFragmentInternal_EXPERIMENTAL.js.flow} +4 -3
  100. package/relay-hooks/{react-cache/useFragmentInternal_REACT_CACHE.js.flow → experimental/useFragmentInternal_EXPERIMENTAL.js.flow} +32 -14
  101. package/relay-hooks/{react-cache/useFragment_REACT_CACHE.js.flow → experimental/useFragment_EXPERIMENTAL.js.flow} +4 -10
  102. package/relay-hooks/{react-cache/usePaginationFragment_REACT_CACHE.js.flow → experimental/usePaginationFragment_EXPERIMENTAL.js.flow} +30 -59
  103. package/relay-hooks/{react-cache/useRefetchableFragmentInternal_REACT_CACHE.js.flow → experimental/useRefetchableFragmentInternal_EXPERIMENTAL.js.flow} +30 -23
  104. package/relay-hooks/experimental/useRefetchableFragment_EXPERIMENTAL.js.flow +49 -0
  105. package/relay-hooks/loadEntryPoint.js.flow +4 -2
  106. package/relay-hooks/loadQuery.js.flow +21 -1
  107. package/relay-hooks/prepareEntryPoint_DEPRECATED.js.flow +4 -2
  108. package/relay-hooks/useBlockingPaginationFragment.js.flow +10 -17
  109. package/relay-hooks/useClientQuery.js.flow +2 -2
  110. package/relay-hooks/useFragmentNode.js.flow +2 -2
  111. package/relay-hooks/useLazyLoadQueryNode.js.flow +17 -1
  112. package/relay-hooks/useLoadMoreFunction.js.flow +15 -9
  113. package/relay-hooks/useMutation.js.flow +26 -9
  114. package/relay-hooks/usePaginationFragment.js.flow +7 -15
  115. package/relay-hooks/useQueryLoader.js.flow +2 -8
  116. package/relay-hooks/useRefetchableFragment.js.flow +14 -16
  117. package/relay-hooks/useRefetchableFragmentNode.js.flow +33 -20
  118. package/lib/relay-hooks/react-cache/RelayReactCache.js +0 -32
  119. package/lib/relay-hooks/react-cache/getQueryResultOrFetchQuery_REACT_CACHE.js +0 -290
  120. package/lib/relay-hooks/react-cache/useLazyLoadQuery_REACT_CACHE.js +0 -49
  121. package/lib/relay-hooks/react-cache/usePreloadedQuery_REACT_CACHE.js +0 -110
  122. package/relay-hooks/react-cache/RelayReactCache.js.flow +0 -40
  123. package/relay-hooks/react-cache/getQueryResultOrFetchQuery_REACT_CACHE.js.flow +0 -430
  124. package/relay-hooks/react-cache/useLazyLoadQuery_REACT_CACHE.js.flow +0 -70
  125. package/relay-hooks/react-cache/usePreloadedQuery_REACT_CACHE.js.flow +0 -150
  126. package/relay-hooks/react-cache/useRefetchableFragment_REACT_CACHE.js.flow +0 -65
@@ -12,22 +12,20 @@
12
12
  'use strict';
13
13
 
14
14
  import type {LoadMoreFn, UseLoadMoreFunctionArgs} from '../useLoadMoreFunction';
15
- import type {Options} from './useRefetchableFragmentInternal_REACT_CACHE';
16
- import type {RefetchFnDynamic} from './useRefetchableFragmentInternal_REACT_CACHE';
15
+ import type {ReturnType} from '../usePaginationFragment';
16
+ import type {Options} from './useRefetchableFragmentInternal_EXPERIMENTAL';
17
17
  import type {
18
18
  FragmentType,
19
19
  GraphQLResponse,
20
- GraphQLTaggedNode,
21
20
  Observer,
22
- OperationType,
21
+ RefetchableFragment,
23
22
  Variables,
24
23
  } from 'relay-runtime';
25
- import type {VariablesOf} from 'relay-runtime/util/RelayRuntimeTypes';
26
24
 
27
25
  const useLoadMoreFunction = require('../useLoadMoreFunction');
28
26
  const useRelayEnvironment = require('../useRelayEnvironment');
29
27
  const useStaticFragmentNodeWarning = require('../useStaticFragmentNodeWarning');
30
- const useRefetchableFragmentInternal = require('./useRefetchableFragmentInternal_REACT_CACHE');
28
+ const useRefetchableFragmentInternal = require('./useRefetchableFragmentInternal_EXPERIMENTAL');
31
29
  const {useCallback, useDebugValue, useState} = require('react');
32
30
  const {
33
31
  getFragment,
@@ -35,36 +33,15 @@ const {
35
33
  getPaginationMetadata,
36
34
  } = require('relay-runtime');
37
35
 
38
- export type ReturnType<TQuery: OperationType, TKey, TFragmentData> = {
39
- data: TFragmentData,
40
- loadNext: LoadMoreFn<TQuery['variables']>,
41
- loadPrevious: LoadMoreFn<TQuery['variables']>,
42
- hasNext: boolean,
43
- hasPrevious: boolean,
44
- isLoadingNext: boolean,
45
- isLoadingPrevious: boolean,
46
- refetch: RefetchFnDynamic<TQuery, TKey>,
47
- };
48
-
49
36
  function usePaginationFragment<
50
- TQuery: OperationType,
51
- TKey: ?{+$data?: mixed, +$fragmentSpreads: FragmentType, ...},
37
+ TFragmentType: FragmentType,
38
+ TVariables: Variables,
39
+ TData,
40
+ TKey: ?{+$fragmentSpreads: TFragmentType, ...},
52
41
  >(
53
- fragmentInput: GraphQLTaggedNode,
42
+ fragmentInput: RefetchableFragment<TFragmentType, TData, TVariables>,
54
43
  parentFragmentRef: TKey,
55
- ): ReturnType<
56
- TQuery,
57
- TKey,
58
- // NOTE: This $Call ensures that the type of the returned data is either:
59
- // - nullable if the provided ref type is nullable
60
- // - non-nullable if the provided ref type is non-nullable
61
- // prettier-ignore
62
- $Call<
63
- & (<TFragmentData>( { +$data?: TFragmentData, ... }) => TFragmentData)
64
- & (<TFragmentData>(?{ +$data?: TFragmentData, ... }) => ?TFragmentData),
65
- TKey,
66
- >,
67
- > {
44
+ ): ReturnType<TVariables, TData, TKey> {
68
45
  const fragmentNode = getFragment(fragmentInput);
69
46
  useStaticFragmentNodeWarning(
70
47
  fragmentNode,
@@ -72,22 +49,18 @@ function usePaginationFragment<
72
49
  );
73
50
  const componentDisplayName = 'usePaginationFragment()';
74
51
 
75
- const {
76
- connectionPathInFragmentData,
77
- paginationRequest,
78
- paginationMetadata,
79
- identifierField,
80
- } = getPaginationMetadata(fragmentNode, componentDisplayName);
52
+ const {connectionPathInFragmentData, paginationRequest, paginationMetadata} =
53
+ getPaginationMetadata(fragmentNode, componentDisplayName);
81
54
 
82
55
  const {fragmentData, fragmentRef, refetch} = useRefetchableFragmentInternal<
83
- TQuery,
84
- TKey,
56
+ {variables: TVariables, response: TData},
57
+ {data?: TData},
85
58
  >(fragmentNode, parentFragmentRef, componentDisplayName);
86
59
  const fragmentIdentifier = getFragmentIdentifier(fragmentNode, fragmentRef);
87
60
 
88
61
  // Backward pagination
89
62
  const [loadPrevious, hasPrevious, isLoadingPrevious, disposeFetchPrevious] =
90
- useLoadMore<TQuery['variables']>({
63
+ useLoadMore<TVariables>({
91
64
  componentDisplayName,
92
65
  connectionPathInFragmentData,
93
66
  direction: 'backward',
@@ -95,29 +68,26 @@ function usePaginationFragment<
95
68
  fragmentIdentifier,
96
69
  fragmentNode,
97
70
  fragmentRef,
98
- identifierField,
99
71
  paginationMetadata,
100
72
  paginationRequest,
101
73
  });
102
74
 
103
75
  // Forward pagination
104
- const [loadNext, hasNext, isLoadingNext, disposeFetchNext] = useLoadMore<
105
- TQuery['variables'],
106
- >({
107
- componentDisplayName,
108
- connectionPathInFragmentData,
109
- direction: 'forward',
110
- fragmentData,
111
- fragmentIdentifier,
112
- fragmentNode,
113
- fragmentRef,
114
- identifierField,
115
- paginationMetadata,
116
- paginationRequest,
117
- });
76
+ const [loadNext, hasNext, isLoadingNext, disposeFetchNext] =
77
+ useLoadMore<TVariables>({
78
+ componentDisplayName,
79
+ connectionPathInFragmentData,
80
+ direction: 'forward',
81
+ fragmentData,
82
+ fragmentIdentifier,
83
+ fragmentNode,
84
+ fragmentRef,
85
+ paginationMetadata,
86
+ paginationRequest,
87
+ });
118
88
 
119
- const refetchPagination: RefetchFnDynamic<TQuery, TKey> = useCallback(
120
- (variables: VariablesOf<TQuery>, options: void | Options) => {
89
+ const refetchPagination = useCallback(
90
+ (variables: TVariables, options: void | Options) => {
121
91
  disposeFetchNext();
122
92
  disposeFetchPrevious();
123
93
  return refetch(variables, {...options, __environment: undefined});
@@ -137,6 +107,7 @@ function usePaginationFragment<
137
107
  });
138
108
  }
139
109
  return {
110
+ // $FlowFixMe[incompatible-return]
140
111
  data: fragmentData,
141
112
  loadNext,
142
113
  loadPrevious,
@@ -11,6 +11,7 @@
11
11
 
12
12
  'use strict';
13
13
 
14
+ import type {RefetchableIdentifierInfo} from '../../../relay-runtime/util/ReaderNode';
14
15
  import type {LoaderFn} from '../useQueryLoader';
15
16
  import type {
16
17
  ConcreteRequest,
@@ -30,8 +31,8 @@ const {getQueryResourceForEnvironment} = require('../QueryResource');
30
31
  const useIsMountedRef = require('../useIsMountedRef');
31
32
  const useQueryLoader = require('../useQueryLoader');
32
33
  const useRelayEnvironment = require('../useRelayEnvironment');
33
- const readFragmentInternal = require('./readFragmentInternal_REACT_CACHE');
34
- const useFragmentInternal = require('./useFragmentInternal_REACT_CACHE');
34
+ const readFragmentInternal = require('./readFragmentInternal_EXPERIMENTAL');
35
+ const useFragmentInternal = require('./useFragmentInternal_EXPERIMENTAL');
35
36
  const invariant = require('invariant');
36
37
  const {useCallback, useContext, useReducer} = require('react');
37
38
  const {
@@ -54,16 +55,13 @@ export type RefetchFn<
54
55
  // /nullable/.
55
56
  // - Or, expects /a subset/ of the query variables if the provided key type is
56
57
  // /non-null/.
57
- // prettier-ignore
58
58
  export type RefetchFnDynamic<
59
59
  TQuery: OperationType,
60
- TKey: ?{ +$data?: mixed, ... },
60
+ TKey: ?{+$data?: mixed, ...},
61
61
  TOptions = Options,
62
- > = $Call<
63
- & (( { +$data?: mixed, ... }) => RefetchFnInexact<TQuery, TOptions>)
64
- & ((?{ +$data?: mixed, ... }) => RefetchFnExact<TQuery, TOptions>),
65
- TKey
66
- >;
62
+ > = [TKey] extends [{+$data?: mixed, ...}]
63
+ ? RefetchFnInexact<TQuery, TOptions>
64
+ : RefetchFnExact<TQuery, TOptions>;
67
65
 
68
66
  export type ReturnType<
69
67
  TQuery: OperationType,
@@ -98,7 +96,7 @@ type RefetchFnExact<TQuery: OperationType, TOptions = Options> = RefetchFnBase<
98
96
  type RefetchFnInexact<
99
97
  TQuery: OperationType,
100
98
  TOptions = Options,
101
- > = RefetchFnBase<Partial<VariablesOf<TQuery>>, TOptions>;
99
+ > = RefetchFnBase<$ReadOnly<Partial<VariablesOf<TQuery>>>, TOptions>;
102
100
 
103
101
  type Action =
104
102
  | {
@@ -171,7 +169,7 @@ function useRefetchableFragmentNode<
171
169
  componentDisplayName: string,
172
170
  ): ReturnType<TQuery, TKey, InternalOptions> {
173
171
  const parentEnvironment = useRelayEnvironment();
174
- const {refetchableRequest, fragmentRefPathInResponse, identifierField} =
172
+ const {refetchableRequest, fragmentRefPathInResponse, identifierInfo} =
175
173
  getRefetchMetadata(fragmentNode, componentDisplayName);
176
174
  const fragmentIdentifier = getFragmentIdentifier(
177
175
  fragmentNode,
@@ -236,6 +234,7 @@ function useRefetchableFragmentNode<
236
234
  debugPreviousIDAndTypename = debugFunctions.getInitialIDAndType(
237
235
  refetchQuery.request.variables,
238
236
  fragmentRefPathInResponse,
237
+ identifierInfo?.identifierQueryVariableName,
239
238
  environment,
240
239
  );
241
240
  }
@@ -343,7 +342,7 @@ function useRefetchableFragmentNode<
343
342
  fragmentIdentifier,
344
343
  fragmentNode,
345
344
  fragmentRefPathInResponse,
346
- identifierField,
345
+ identifierInfo,
347
346
  loadQuery,
348
347
  parentFragmentRef,
349
348
  refetchableRequest,
@@ -351,6 +350,7 @@ function useRefetchableFragmentNode<
351
350
  return {
352
351
  fragmentData,
353
352
  fragmentRef,
353
+ // $FlowFixMe[incompatible-return] RefetchFn not compatible with RefetchFnDynamic
354
354
  refetch,
355
355
  };
356
356
  }
@@ -377,17 +377,17 @@ function useRefetchFunction<TQuery: OperationType>(
377
377
  fragmentIdentifier: string,
378
378
  fragmentNode: ReaderFragment,
379
379
  fragmentRefPathInResponse: $ReadOnlyArray<string | number>,
380
- identifierField: ?string,
380
+ identifierInfo: ?RefetchableIdentifierInfo,
381
381
  loadQuery: LoaderFn<TQuery>,
382
382
  parentFragmentRef: mixed,
383
383
  refetchableRequest: ConcreteRequest,
384
384
  ): RefetchFn<TQuery, InternalOptions> {
385
385
  const isMountedRef = useIsMountedRef();
386
386
  const identifierValue =
387
- identifierField != null &&
387
+ identifierInfo?.identifierField != null &&
388
388
  fragmentData != null &&
389
389
  typeof fragmentData === 'object'
390
- ? fragmentData[identifierField]
390
+ ? fragmentData[identifierInfo.identifierField]
391
391
  : null;
392
392
  return useCallback(
393
393
  (
@@ -454,8 +454,10 @@ function useRefetchFunction<TQuery: OperationType>(
454
454
  // If the query needs an identifier value ('id' or similar) and one
455
455
  // was not explicitly provided, read it from the fragment data.
456
456
  if (
457
- identifierField != null &&
458
- !providedRefetchVariables.hasOwnProperty('id')
457
+ identifierInfo != null &&
458
+ !providedRefetchVariables.hasOwnProperty(
459
+ identifierInfo.identifierQueryVariableName,
460
+ )
459
461
  ) {
460
462
  // @refetchable fragments are guaranteed to have an `id` selection
461
463
  // if the type is Node, implements Node, or is @fetchable. Double-check
@@ -465,21 +467,25 @@ function useRefetchFunction<TQuery: OperationType>(
465
467
  false,
466
468
  'Relay: Expected result to have a string ' +
467
469
  '`%s` in order to refetch, got `%s`.',
468
- identifierField,
470
+ identifierInfo.identifierField,
469
471
  identifierValue,
470
472
  );
471
473
  }
472
- (refetchVariables: $FlowFixMe).id = identifierValue;
474
+ (refetchVariables: $FlowFixMe)[
475
+ identifierInfo.identifierQueryVariableName
476
+ ] = identifierValue;
473
477
  }
474
478
 
475
479
  const refetchQuery = createOperationDescriptor(
476
480
  refetchableRequest,
477
481
  refetchVariables,
478
- {force: true},
482
+ {
483
+ force: true,
484
+ },
479
485
  );
480
486
 
481
487
  // We call loadQuery which will start a network request if necessary
482
- // and update the querRef from useQueryLoader.
488
+ // and update the queryRef from useQueryLoader.
483
489
  // Note the following:
484
490
  // - loadQuery will dispose of any previously refetched queries.
485
491
  // - We use the variables extracted off the OperationDescriptor
@@ -518,10 +524,11 @@ if (__DEV__) {
518
524
  getInitialIDAndType(
519
525
  memoRefetchVariables: ?Variables,
520
526
  fragmentRefPathInResponse: $ReadOnlyArray<string | number>,
527
+ identifierQueryVariableName: ?string,
521
528
  environment: IEnvironment,
522
529
  ): ?DebugIDandTypename {
523
530
  const {Record} = require('relay-runtime');
524
- const id = memoRefetchVariables?.id;
531
+ const id = memoRefetchVariables?.[identifierQueryVariableName ?? 'id'];
525
532
  if (
526
533
  fragmentRefPathInResponse.length !== 1 ||
527
534
  fragmentRefPathInResponse[0] !== 'node' ||
@@ -531,7 +538,7 @@ if (__DEV__) {
531
538
  }
532
539
  const recordSource = environment.getStore().getSource();
533
540
  const record = recordSource.get(id);
534
- const typename = record && Record.getType(record);
541
+ const typename = record == null ? null : Record.getType(record);
535
542
  if (typename == null) {
536
543
  return null;
537
544
  }
@@ -0,0 +1,49 @@
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 {ReturnType} from '../useRefetchableFragment';
15
+ import type {FragmentType, RefetchableFragment, Variables} from 'relay-runtime';
16
+
17
+ const useStaticFragmentNodeWarning = require('../useStaticFragmentNodeWarning');
18
+ const useRefetchableFragmentInternal = require('./useRefetchableFragmentInternal_EXPERIMENTAL');
19
+ const {useDebugValue} = require('react');
20
+ const {getFragment} = require('relay-runtime');
21
+
22
+ function useRefetchableFragment<
23
+ TFragmentType: FragmentType,
24
+ TVariables: Variables,
25
+ TData,
26
+ TKey: ?{+$fragmentSpreads: TFragmentType, ...},
27
+ >(
28
+ fragmentInput: RefetchableFragment<TFragmentType, TData, TVariables>,
29
+ fragmentRef: TKey,
30
+ ): ReturnType<TVariables, TData, TKey> {
31
+ const fragmentNode = getFragment(fragmentInput);
32
+ useStaticFragmentNodeWarning(
33
+ fragmentNode,
34
+ 'first argument of useRefetchableFragment()',
35
+ );
36
+ const {fragmentData, refetch} = useRefetchableFragmentInternal<
37
+ {variables: TVariables, response: TData},
38
+ {data?: TData},
39
+ >(fragmentNode, fragmentRef, 'useRefetchableFragment()');
40
+ if (__DEV__) {
41
+ // eslint-disable-next-line react-hooks/rules-of-hooks
42
+ useDebugValue({fragment: fragmentNode.name, data: fragmentData});
43
+ }
44
+ // $FlowFixMe[incompatible-return]
45
+ // $FlowFixMe[prop-missing]
46
+ return [fragmentData, refetch];
47
+ }
48
+
49
+ module.exports = useRefetchableFragment;
@@ -46,8 +46,10 @@ function loadEntryPoint<
46
46
  }
47
47
  const preloadProps = entryPoint.getPreloadProps(entryPointParams);
48
48
  const {queries, entryPoints, extraProps} = preloadProps;
49
- const preloadedQueries: $Shape<TPreloadedQueries> = {};
50
- const preloadedEntryPoints: $Shape<TPreloadedEntryPoints> = {};
49
+ // $FlowFixMe[incompatible-type]
50
+ const preloadedQueries: Partial<TPreloadedQueries> = {};
51
+ // $FlowFixMe[incompatible-type]
52
+ const preloadedEntryPoints: Partial<TPreloadedEntryPoints> = {};
51
53
  if (queries != null) {
52
54
  const queriesPropNames = Object.keys(queries);
53
55
  queriesPropNames.forEach(queryPropName => {
@@ -24,6 +24,7 @@ import type {
24
24
  IEnvironment,
25
25
  OperationDescriptor,
26
26
  OperationType,
27
+ Query,
27
28
  RequestIdentifier,
28
29
  RequestParameters,
29
30
  } from 'relay-runtime';
@@ -56,12 +57,31 @@ function useTrackLoadQueryInRender() {
56
57
  }
57
58
  }
58
59
 
60
+ type QueryType<T> = T extends Query<infer V, infer D, infer RR>
61
+ ? {
62
+ variables: V,
63
+ response: D,
64
+ rawResponse?: $NonMaybeType<RR>,
65
+ }
66
+ : $Call<<T>(PreloadableConcreteRequest<T>) => T, T>;
67
+
68
+ declare function loadQuery<
69
+ T,
70
+ TEnvironmentProviderOptions = EnvironmentProviderOptions,
71
+ >(
72
+ environment: IEnvironment,
73
+ preloadableRequest: T,
74
+ variables: QueryType<T>['variables'],
75
+ options?: ?LoadQueryOptions,
76
+ environmentProviderOptions?: ?TEnvironmentProviderOptions,
77
+ ): PreloadedQueryInner<QueryType<T>, TEnvironmentProviderOptions>;
78
+
59
79
  function loadQuery<
60
80
  TQuery: OperationType,
61
81
  TEnvironmentProviderOptions = EnvironmentProviderOptions,
62
82
  >(
63
83
  environment: IEnvironment,
64
- preloadableRequest: GraphQLTaggedNode | PreloadableConcreteRequest<TQuery>,
84
+ preloadableRequest: PreloadableConcreteRequest<TQuery>,
65
85
  variables: TQuery['variables'],
66
86
  options?: ?LoadQueryOptions,
67
87
  environmentProviderOptions?: ?TEnvironmentProviderOptions,
@@ -45,8 +45,10 @@ function prepareEntryPoint<
45
45
  }
46
46
  const preloadProps = entryPoint.getPreloadProps(entryPointParams);
47
47
  const {queries, entryPoints} = preloadProps;
48
- const preloadedQueries: $Shape<TPreloadedQueries> = {};
49
- const preloadedEntryPoints: $Shape<TPreloadedEntryPoints> = {};
48
+ // $FlowFixMe[incompatible-type]
49
+ const preloadedQueries: Partial<TPreloadedQueries> = {};
50
+ // $FlowFixMe[incompatible-type]
51
+ const preloadedEntryPoints: Partial<TPreloadedEntryPoints> = {};
50
52
  if (queries != null) {
51
53
  const queriesPropNames = Object.keys(queries);
52
54
  queriesPropNames.forEach(queryPropName => {
@@ -34,15 +34,12 @@ const {
34
34
  } = require('relay-runtime');
35
35
 
36
36
  type RefetchVariables<TVariables, TKey> =
37
- // NOTE: This $Call ensures that the type of the variables is either:
37
+ // NOTE: This type ensures that the type of the variables is either:
38
38
  // - nullable if the provided ref type is non-nullable
39
39
  // - non-nullable if the provided ref type is nullable, and the caller need to provide the full set of variables
40
- // prettier-ignore
41
- $Call<
42
- & (<TFragmentType>( { +$fragmentSpreads: TFragmentType, ... }) => $Shape<TVariables>)
43
- & (<TFragmentType>(?{ +$fragmentSpreads: TFragmentType, ... }) => TVariables),
44
- TKey,
45
- >;
40
+ [+key: TKey] extends [+key: {+$fragmentSpreads: mixed, ...}]
41
+ ? Partial<TVariables>
42
+ : TVariables;
46
43
 
47
44
  type RefetchFnBase<TVars, TOptions> = (
48
45
  vars: TVars,
@@ -55,15 +52,12 @@ type RefetchFn<TVariables, TKey, TOptions = Options> = RefetchFnBase<
55
52
  >;
56
53
 
57
54
  type ReturnType<TVariables, TData, TKey> = {
58
- // NOTE: This $Call ensures that the type of the returned data is either:
55
+ // NOTE: This rtpw ensures that the type of the returned data is either:
59
56
  // - nullable if the provided ref type is nullable
60
57
  // - non-nullable if the provided ref type is non-nullable
61
- // prettier-ignore
62
- data: $Call<
63
- & (<TFragmentType>( { +$fragmentSpreads: TFragmentType, ... }) => TData)
64
- & (<TFragmentType>(?{ +$fragmentSpreads: TFragmentType, ... }) => ?TData),
65
- TKey,
66
- >,
58
+ data: [+key: TKey] extends [+key: {+$fragmentSpreads: mixed, ...}]
59
+ ? TData
60
+ : ?TData,
67
61
  loadNext: LoadMoreFn<TVariables>,
68
62
  loadPrevious: LoadMoreFn<TVariables>,
69
63
  hasNext: boolean,
@@ -89,7 +83,6 @@ function useBlockingPaginationFragment<
89
83
 
90
84
  const {
91
85
  connectionPathInFragmentData,
92
- identifierField,
93
86
  paginationRequest,
94
87
  paginationMetadata,
95
88
  stream,
@@ -132,7 +125,6 @@ function useBlockingPaginationFragment<
132
125
  fragmentIdentifier,
133
126
  fragmentNode,
134
127
  fragmentRef,
135
- identifierField,
136
128
  paginationMetadata,
137
129
  paginationRequest,
138
130
  });
@@ -148,7 +140,6 @@ function useBlockingPaginationFragment<
148
140
  fragmentIdentifier,
149
141
  fragmentNode,
150
142
  fragmentRef,
151
- identifierField,
152
143
  paginationMetadata,
153
144
  paginationRequest,
154
145
  });
@@ -157,6 +148,7 @@ function useBlockingPaginationFragment<
157
148
  (variables: TVariables, options: void | Options) => {
158
149
  disposeFetchNext();
159
150
  disposeFetchPrevious();
151
+ // $FlowFixMe[incompatible-variance]
160
152
  return refetch(variables, {...options, __environment: undefined});
161
153
  },
162
154
  [disposeFetchNext, disposeFetchPrevious, refetch],
@@ -164,6 +156,7 @@ function useBlockingPaginationFragment<
164
156
 
165
157
  return {
166
158
  // $FlowFixMe[incompatible-cast]
159
+ // $FlowFixMe[incompatible-return]
167
160
  data: (fragmentData: TData),
168
161
  loadNext,
169
162
  loadPrevious,
@@ -20,8 +20,8 @@ const useLazyLoadQuery = require('./useLazyLoadQuery');
20
20
  * These queries are consist of queries for client-only data,
21
21
  * schematized via local schema extensions and/or Relay resolvers.
22
22
  */
23
- function useClientQuery<TVariables: Variables, TData>(
24
- gqlQuery: ClientQuery<TVariables, TData>,
23
+ function useClientQuery<TVariables: Variables, TData, TRawResponse>(
24
+ gqlQuery: ClientQuery<TVariables, TData, TRawResponse>,
25
25
  variables: TVariables,
26
26
  options?: {
27
27
  UNSTABLE_renderPolicy?: RenderPolicy,
@@ -17,7 +17,7 @@ const {getFragmentResourceForEnvironment} = require('./FragmentResource');
17
17
  const useRelayEnvironment = require('./useRelayEnvironment');
18
18
  const useUnsafeRef_DEPRECATED = require('./useUnsafeRef_DEPRECATED');
19
19
  const {useEffect, useState} = require('react');
20
- const {getFragmentIdentifier} = require('relay-runtime');
20
+ const {RelayFeatureFlags, getFragmentIdentifier} = require('relay-runtime');
21
21
  const warning = require('warning');
22
22
 
23
23
  type ReturnType<TFragmentData: mixed> = {
@@ -99,7 +99,7 @@ function useFragmentNode<TFragmentData: mixed>(
99
99
  // eslint-disable-next-line react-hooks/exhaustive-deps
100
100
  }, [environment, fragmentIdentifier]);
101
101
 
102
- if (__DEV__) {
102
+ if (RelayFeatureFlags.LOG_MISSING_RECORDS_IN_PROD || __DEV__) {
103
103
  if (
104
104
  fragmentRef != null &&
105
105
  (fragmentResult.data === undefined ||
@@ -19,7 +19,9 @@ import type {
19
19
  OperationType,
20
20
  RenderPolicy,
21
21
  } from 'relay-runtime';
22
+ import type {ReaderFragment} from 'relay-runtime/util/ReaderNode';
22
23
 
24
+ const HooksImplementation = require('./HooksImplementation');
23
25
  const ProfilerContext = require('./ProfilerContext');
24
26
  const {
25
27
  getQueryCacheIdentifier,
@@ -125,7 +127,7 @@ function useLazyLoadQueryNode<TQuery: OperationType>({
125
127
  });
126
128
 
127
129
  const {fragmentNode, fragmentRef} = preparedQueryResult;
128
- const {data} = useFragmentNode<$FlowFixMe>(
130
+ const data = useFragmentNodeImpl(
129
131
  fragmentNode,
130
132
  fragmentRef,
131
133
  componentDisplayName,
@@ -133,4 +135,18 @@ function useLazyLoadQueryNode<TQuery: OperationType>({
133
135
  return data;
134
136
  }
135
137
 
138
+ function useFragmentNodeImpl(
139
+ fragment: ReaderFragment,
140
+ key: mixed,
141
+ componentDisplayName: string,
142
+ ): mixed {
143
+ const impl = HooksImplementation.get();
144
+ if (impl && impl.useFragment__internal) {
145
+ return impl.useFragment__internal(fragment, key, componentDisplayName);
146
+ } else {
147
+ const {data} = useFragmentNode<mixed>(fragment, key, componentDisplayName);
148
+ return data;
149
+ }
150
+ }
151
+
136
152
  module.exports = useLazyLoadQueryNode;
@@ -33,6 +33,7 @@ const {
33
33
  ConnectionInterface,
34
34
  createOperationDescriptor,
35
35
  getPaginationVariables,
36
+ getRefetchMetadata,
36
37
  getSelector,
37
38
  getValueAtPath,
38
39
  } = require('relay-runtime');
@@ -42,7 +43,7 @@ export type LoadMoreFn<TVariables: Variables> = (
42
43
  count: number,
43
44
  options?: {
44
45
  onComplete?: (Error | null) => void,
45
- UNSTABLE_extraVariables?: $Shape<TVariables>,
46
+ UNSTABLE_extraVariables?: Partial<TVariables>,
46
47
  },
47
48
  ) => Disposable;
48
49
 
@@ -53,7 +54,6 @@ export type UseLoadMoreFunctionArgs = {
53
54
  fragmentIdentifier: string,
54
55
  fragmentData: mixed,
55
56
  connectionPathInFragmentData: $ReadOnlyArray<string | number>,
56
- identifierField: ?string,
57
57
  paginationRequest: ConcreteRequest,
58
58
  paginationMetadata: ReaderPaginationMetadata,
59
59
  componentDisplayName: string,
@@ -76,17 +76,22 @@ function useLoadMoreFunction<TVariables: Variables>(
76
76
  componentDisplayName,
77
77
  observer,
78
78
  onReset,
79
- identifierField,
80
79
  } = args;
81
80
  const environment = useRelayEnvironment();
82
81
  const {isFetchingRef, startFetch, disposeFetch, completeFetch} =
83
82
  useFetchTrackingRef();
83
+
84
+ const {identifierInfo} = getRefetchMetadata(
85
+ fragmentNode,
86
+ componentDisplayName,
87
+ );
84
88
  const identifierValue =
85
- identifierField != null &&
89
+ identifierInfo?.identifierField != null &&
86
90
  fragmentData != null &&
87
91
  typeof fragmentData === 'object'
88
- ? fragmentData[identifierField]
92
+ ? fragmentData[identifierInfo.identifierField]
89
93
  : null;
94
+
90
95
  const isMountedRef = useIsMountedRef();
91
96
  const [mirroredEnvironment, setMirroredEnvironment] = useState(environment);
92
97
  const [mirroredFragmentIdentifier, setMirroredFragmentIdentifier] =
@@ -125,7 +130,7 @@ function useLoadMoreFunction<TVariables: Variables>(
125
130
  (
126
131
  count: number,
127
132
  options: void | {
128
- UNSTABLE_extraVariables?: $Shape<TVariables>,
133
+ UNSTABLE_extraVariables?: Partial<TVariables>,
129
134
  onComplete?: (Error | null) => void,
130
135
  },
131
136
  ) => {
@@ -201,7 +206,7 @@ function useLoadMoreFunction<TVariables: Variables>(
201
206
 
202
207
  // If the query needs an identifier value ('id' or similar) and one
203
208
  // was not explicitly provided, read it from the fragment data.
204
- if (identifierField != null) {
209
+ if (identifierInfo != null) {
205
210
  // @refetchable fragments are guaranteed to have an `id` selection
206
211
  // if the type is Node, implements Node, or is @fetchable. Double-check
207
212
  // that there actually is a value at runtime.
@@ -210,11 +215,12 @@ function useLoadMoreFunction<TVariables: Variables>(
210
215
  false,
211
216
  'Relay: Expected result to have a string ' +
212
217
  '`%s` in order to refetch, got `%s`.',
213
- identifierField,
218
+ identifierInfo.identifierField,
214
219
  identifierValue,
215
220
  );
216
221
  }
217
- paginationVariables.id = identifierValue;
222
+ paginationVariables[identifierInfo.identifierQueryVariableName] =
223
+ identifierValue;
218
224
  }
219
225
 
220
226
  const paginationQuery = createOperationDescriptor(