react-relay 15.0.0 → 16.1.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 (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(