react-relay 18.1.0 → 19.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 (67) hide show
  1. package/ReactRelayContainerUtils.js.flow +2 -2
  2. package/ReactRelayContext.js +1 -1
  3. package/ReactRelayFragmentContainer.js.flow +5 -10
  4. package/ReactRelayLoggingContext.js.flow +21 -0
  5. package/ReactRelayPaginationContainer.js.flow +8 -8
  6. package/ReactRelayRefetchContainer.js.flow +8 -8
  7. package/ReactRelayTypes.js.flow +18 -11
  8. package/__flowtests__/ReactRelayFragmentContainer-flowtest.js.flow +1 -8
  9. package/__flowtests__/ReactRelayPaginationContainer-flowtest.js.flow +2 -5
  10. package/__flowtests__/ReactRelayRefetchContainer-flowtest.js.flow +2 -5
  11. package/buildReactRelayContainer.js.flow +3 -3
  12. package/hooks.js +1 -1
  13. package/index.js +1 -1
  14. package/index.js.flow +3 -0
  15. package/legacy.js +1 -1
  16. package/lib/ReactRelayLoggingContext.js +6 -0
  17. package/lib/index.js +2 -0
  18. package/lib/relay-hooks/legacy/FragmentResource.js +4 -5
  19. package/lib/relay-hooks/legacy/useRefetchableFragmentNode.js +1 -1
  20. package/lib/relay-hooks/loadEntryPoint.js +3 -0
  21. package/lib/relay-hooks/loadQuery.js +9 -16
  22. package/lib/relay-hooks/preloadQuery_DEPRECATED.js +7 -2
  23. package/lib/relay-hooks/readFragmentInternal.js +2 -2
  24. package/lib/relay-hooks/useFragmentInternal_CURRENT.js +12 -8
  25. package/lib/relay-hooks/useFragmentInternal_EXPERIMENTAL.js +12 -8
  26. package/lib/relay-hooks/useLoadMoreFunction.js +3 -2
  27. package/lib/relay-hooks/useLoadMoreFunction_EXPERIMENTAL.js +3 -2
  28. package/lib/relay-hooks/usePaginationFragment.js +5 -1
  29. package/lib/relay-hooks/usePrefetchableForwardPaginationFragment.js +228 -0
  30. package/lib/relay-hooks/usePrefetchableForwardPaginationFragment_EXPERIMENTAL.js +227 -0
  31. package/lib/relay-hooks/useRefetchableFragmentInternal.js +3 -3
  32. package/lib/relay-hooks/useRelayLoggingContext.js +9 -0
  33. package/package.json +3 -3
  34. package/relay-hooks/EntryPointContainer.react.js.flow +13 -17
  35. package/relay-hooks/EntryPointTypes.flow.js.flow +7 -5
  36. package/relay-hooks/MatchContainer.js.flow +1 -1
  37. package/relay-hooks/legacy/FragmentResource.js.flow +5 -9
  38. package/relay-hooks/legacy/useBlockingPaginationFragment.js.flow +2 -17
  39. package/relay-hooks/legacy/useRefetchableFragmentNode.js.flow +1 -1
  40. package/relay-hooks/loadEntryPoint.js.flow +6 -0
  41. package/relay-hooks/loadQuery.js.flow +47 -39
  42. package/relay-hooks/preloadQuery_DEPRECATED.js.flow +18 -3
  43. package/relay-hooks/readFragmentInternal.js.flow +2 -5
  44. package/relay-hooks/useEntryPointLoader.js.flow +4 -2
  45. package/relay-hooks/useFragment.js.flow +1 -0
  46. package/relay-hooks/useFragmentInternal.js.flow +2 -0
  47. package/relay-hooks/useFragmentInternal_CURRENT.js.flow +27 -12
  48. package/relay-hooks/useFragmentInternal_EXPERIMENTAL.js.flow +29 -12
  49. package/relay-hooks/useLazyLoadQuery.js.flow +4 -4
  50. package/relay-hooks/useLoadMoreFunction.js.flow +7 -7
  51. package/relay-hooks/useLoadMoreFunction_EXPERIMENTAL.js.flow +5 -7
  52. package/relay-hooks/usePaginationFragment.js.flow +6 -10
  53. package/relay-hooks/usePrefetchableForwardPaginationFragment.js.flow +436 -0
  54. package/relay-hooks/usePrefetchableForwardPaginationFragment_EXPERIMENTAL.js.flow +435 -0
  55. package/relay-hooks/usePreloadedQuery.js.flow +1 -0
  56. package/relay-hooks/useQueryLoader.js.flow +5 -1
  57. package/relay-hooks/useQueryLoader_EXPERIMENTAL.js.flow +3 -1
  58. package/relay-hooks/useRefetchableFragment.js.flow +1 -0
  59. package/relay-hooks/useRefetchableFragmentInternal.js.flow +3 -3
  60. package/relay-hooks/useRelayLoggingContext.js.flow +21 -0
  61. package/relay-hooks/useStaticFragmentNodeWarning.js.flow +1 -0
  62. package/react-relay-hooks.js +0 -4
  63. package/react-relay-hooks.min.js +0 -9
  64. package/react-relay-legacy.js +0 -4
  65. package/react-relay-legacy.min.js +0 -9
  66. package/react-relay.js +0 -4
  67. package/react-relay.min.js +0 -9
@@ -0,0 +1,435 @@
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 {RefetchFn} from './useRefetchableFragment';
15
+ import type {Options} from './useRefetchableFragmentInternal';
16
+ import type {FragmentType, Variables} from 'relay-runtime';
17
+ import type {PrefetchableRefetchableFragment} from 'relay-runtime';
18
+
19
+ const useFragment = require('./useFragment');
20
+ const useLoadMoreFunction = require('./useLoadMoreFunction');
21
+ const useRefetchableFragmentInternal = require('./useRefetchableFragmentInternal');
22
+ const useRelayEnvironment = require('./useRelayEnvironment');
23
+ const useStaticFragmentNodeWarning = require('./useStaticFragmentNodeWarning');
24
+ const invariant = require('invariant');
25
+ const {
26
+ useCallback,
27
+ useDebugValue,
28
+ useEffect,
29
+ useLayoutEffect,
30
+ useMemo,
31
+ useRef,
32
+ useState,
33
+ } = require('react');
34
+ const {
35
+ getFragment,
36
+ getFragmentIdentifier,
37
+ getPaginationMetadata,
38
+ } = require('relay-runtime');
39
+ const {
40
+ ConnectionInterface,
41
+ RelayFeatureFlags,
42
+ getSelector,
43
+ getValueAtPath,
44
+ } = require('relay-runtime');
45
+
46
+ type LoadMoreFn<TVariables: Variables> = (
47
+ count: number,
48
+ options?: {
49
+ onComplete?: (Error | null) => void,
50
+ UNSTABLE_extraVariables?: Partial<TVariables>,
51
+ },
52
+ ) => void;
53
+
54
+ export type ReturnType<TVariables, TData, TEdgeData, TKey> = {
55
+ // NOTE: This type ensures that the type of the returned data is either:
56
+ // - nullable if the provided ref type is nullable
57
+ // - non-nullable if the provided ref type is non-nullable
58
+ data: [+key: TKey] extends [+key: {+$fragmentSpreads: mixed, ...}]
59
+ ? TData
60
+ : ?TData,
61
+ loadNext: LoadMoreFn<TVariables>,
62
+ hasNext: boolean,
63
+ isLoadingNext: boolean,
64
+ refetch: RefetchFn<TVariables, TKey>,
65
+ edges: TEdgeData,
66
+ };
67
+
68
+ type LoadMoreOptions<TVariables> = {
69
+ UNSTABLE_extraVariables?: Partial<TVariables>,
70
+ onComplete?: (Error | null) => void,
71
+ };
72
+
73
+ export type GetExtraVariablesFn<TEdgeData, TData, TVariables, TKey> = ({
74
+ hasNext: boolean,
75
+ data: [+key: TKey] extends [+key: {+$fragmentSpreads: mixed, ...}]
76
+ ? TData
77
+ : ?TData,
78
+ getServerEdges: () => TEdgeData,
79
+ }) => Partial<TVariables>;
80
+
81
+ hook usePrefetchableForwardPaginationFragment_EXPERIMENTAL<
82
+ TFragmentType: FragmentType,
83
+ TVariables: Variables,
84
+ TData,
85
+ TEdgeData,
86
+ TKey: ?{+$fragmentSpreads: TFragmentType, ...},
87
+ >(
88
+ fragmentInput: PrefetchableRefetchableFragment<
89
+ TFragmentType,
90
+ TData,
91
+ TEdgeData,
92
+ TVariables,
93
+ >,
94
+ parentFragmentRef: TKey,
95
+ bufferSize: number,
96
+ initialSize?: ?number,
97
+ prefetchingLoadMoreOptions?: {
98
+ UNSTABLE_extraVariables?:
99
+ | Partial<TVariables>
100
+ | GetExtraVariablesFn<TEdgeData, TData, TVariables, TKey>,
101
+ onComplete?: (Error | null) => void,
102
+ },
103
+ minimalFetchSize: number = 1,
104
+ ): ReturnType<TVariables, TData, TEdgeData, TKey> {
105
+ const fragmentNode = getFragment(fragmentInput);
106
+ useStaticFragmentNodeWarning(
107
+ fragmentNode,
108
+ 'first argument of usePrefetchableForwardPaginationFragment_EXPERIMENTAL()',
109
+ );
110
+ const componentDisplayName =
111
+ 'usePrefetchableForwardPaginationFragment_EXPERIMENTAL()';
112
+
113
+ const {connectionPathInFragmentData, paginationRequest, paginationMetadata} =
114
+ getPaginationMetadata(fragmentNode, componentDisplayName);
115
+
116
+ const {fragmentData, fragmentRef, refetch} = useRefetchableFragmentInternal<
117
+ {variables: TVariables, response: TData},
118
+ {data?: TData},
119
+ >(fragmentNode, parentFragmentRef, componentDisplayName);
120
+ // TODO: Get rid of `getFragmentIdentifier`
121
+ const fragmentIdentifier = getFragmentIdentifier(fragmentNode, fragmentRef);
122
+
123
+ const edgeKeys = useMemo(() => {
124
+ const connection = getValueAtPath(
125
+ fragmentData,
126
+ connectionPathInFragmentData,
127
+ );
128
+ if (connection == null) {
129
+ return null;
130
+ }
131
+ const {EDGES} = ConnectionInterface.get();
132
+ // $FlowFixMe[incompatible-use]
133
+ return connection[EDGES];
134
+ }, [connectionPathInFragmentData, fragmentData]);
135
+
136
+ const sourceSize = edgeKeys == null ? -1 : edgeKeys.length;
137
+
138
+ const [_numInUse, setNumInUse] = useState(
139
+ initialSize != null ? initialSize : sourceSize,
140
+ );
141
+ let numInUse = _numInUse;
142
+ // We can only reset the source size when the component is
143
+ // updated with new edgeKeys
144
+ if (_numInUse === -1 && sourceSize !== -1) {
145
+ numInUse = initialSize != null ? initialSize : sourceSize;
146
+ setNumInUse(numInUse);
147
+ }
148
+
149
+ const environment = useRelayEnvironment();
150
+ const [isLoadingMore, reallySetIsLoadingMore] = useState(false);
151
+ const [isRefetching, setIsRefetching] = useState(false);
152
+ const availableSizeRef = useRef(0);
153
+ // Schedule this update since it must be observed by components at the same
154
+ // batch as when hasNext changes. hasNext is read from the store and store
155
+ // updates are scheduled, so this must be scheduled too.
156
+ const setIsLoadingMore = useCallback(
157
+ (value: boolean) => {
158
+ const schedule = environment.getScheduler()?.schedule;
159
+ if (schedule) {
160
+ schedule(() => {
161
+ reallySetIsLoadingMore(value);
162
+ });
163
+ } else {
164
+ reallySetIsLoadingMore(value);
165
+ }
166
+ },
167
+ [environment],
168
+ );
169
+
170
+ // `isLoadingMore` state is updated in a low priority, internally we need
171
+ // to synchronously get the loading state to decide whether to load more
172
+ const isLoadingMoreRef = useRef(false);
173
+
174
+ const observer = useMemo(() => {
175
+ function setIsLoadingFalse() {
176
+ isLoadingMoreRef.current = false;
177
+ setIsLoadingMore(false);
178
+ }
179
+ return {
180
+ start: () => {
181
+ isLoadingMoreRef.current = true;
182
+ // We want to make sure that `isLoadingMore` is updated immediately, to avoid
183
+ // product code triggering multiple `loadMore` calls
184
+ reallySetIsLoadingMore(true);
185
+ },
186
+ complete: setIsLoadingFalse,
187
+ error: setIsLoadingFalse,
188
+ unsubscribe: RelayFeatureFlags.ENABLE_USE_PAGINATION_IS_LOADING_FIX
189
+ ? setIsLoadingFalse
190
+ : undefined,
191
+ };
192
+ }, [setIsLoadingMore]);
193
+ const handleReset = useCallback(() => {
194
+ if (!isRefetching) {
195
+ // Do not reset items count during refetching
196
+ const schedule = environment.getScheduler()?.schedule;
197
+ if (schedule) {
198
+ schedule(() => {
199
+ setNumInUse(-1);
200
+ });
201
+ } else {
202
+ setNumInUse(-1);
203
+ }
204
+ }
205
+ isLoadingMoreRef.current = false;
206
+ setIsLoadingMore(false);
207
+ }, [environment, isRefetching, setIsLoadingMore]);
208
+
209
+ const [loadMore, hasNext, disposeFetchNext] = useLoadMoreFunction<TVariables>(
210
+ {
211
+ componentDisplayName,
212
+ connectionPathInFragmentData,
213
+ direction: 'forward',
214
+ fragmentData,
215
+ fragmentIdentifier,
216
+ fragmentNode,
217
+ fragmentRef,
218
+ paginationMetadata,
219
+ paginationRequest,
220
+ observer,
221
+ onReset: handleReset,
222
+ },
223
+ );
224
+
225
+ useLayoutEffect(() => {
226
+ // Make sure `availableSize` is updated before `showMore` from current render can be called
227
+ availableSizeRef.current = sourceSize - numInUse;
228
+ }, [numInUse, sourceSize]);
229
+
230
+ const prefetchingUNSTABLE_extraVariables =
231
+ prefetchingLoadMoreOptions?.UNSTABLE_extraVariables;
232
+ const prefetchingOnComplete = prefetchingLoadMoreOptions?.onComplete;
233
+
234
+ const showMore = useCallback(
235
+ (numToAdd: number, options?: LoadMoreOptions<TVariables>) => {
236
+ // Matches the behavior of `usePaginationFragment`. If there is a `loadMore` ongoing,
237
+ // the hook handles making the `loadMore` a no-op.
238
+ if (!isLoadingMoreRef.current || availableSizeRef.current >= 0) {
239
+ // Preemtively update `availableSizeRef`, so if two `loadMore` is called in the same tick,
240
+ // a second `loadMore` can be no-op
241
+ availableSizeRef.current -= numToAdd;
242
+
243
+ setNumInUse(lastNumInUse => {
244
+ return lastNumInUse + numToAdd;
245
+ });
246
+
247
+ // If the product needs more items from network, load the amount needed to fullfil
248
+ // the requirement and cache, capped at the current amount defined by product
249
+ if (!isLoadingMoreRef.current && availableSizeRef.current < 0) {
250
+ loadMore(
251
+ Math.max(
252
+ minimalFetchSize,
253
+ Math.min(numToAdd, bufferSize - availableSizeRef.current),
254
+ ),
255
+ // Keep options For backward compatibility
256
+ options ?? {
257
+ onComplete: prefetchingOnComplete,
258
+ UNSTABLE_extraVariables:
259
+ typeof prefetchingUNSTABLE_extraVariables === 'function'
260
+ ? // $FlowFixMe[incompatible-call]
261
+ prefetchingUNSTABLE_extraVariables({
262
+ hasNext,
263
+ // $FlowFixMe[incompatible-call]
264
+ data: fragmentData,
265
+ getServerEdges: () => {
266
+ const selector = getSelector(
267
+ // $FlowFixMe[incompatible-call]
268
+ edgesFragment,
269
+ edgeKeys,
270
+ );
271
+ if (selector == null) {
272
+ // $FlowFixMe[incompatible-call]
273
+ return [];
274
+ }
275
+ invariant(
276
+ selector.kind === 'PluralReaderSelector',
277
+ 'Expected a plural selector',
278
+ );
279
+ // $FlowFixMe[incompatible-call]
280
+ return selector.selectors.map(
281
+ sel => environment.lookup(sel).data,
282
+ );
283
+ },
284
+ })
285
+ : prefetchingUNSTABLE_extraVariables,
286
+ },
287
+ );
288
+ }
289
+ }
290
+ },
291
+ [
292
+ bufferSize,
293
+ loadMore,
294
+ minimalFetchSize,
295
+ edgeKeys,
296
+ fragmentData,
297
+ prefetchingUNSTABLE_extraVariables,
298
+ prefetchingOnComplete,
299
+ ],
300
+ );
301
+
302
+ const edgesFragment = fragmentInput.metadata?.refetch?.edgesFragment;
303
+ invariant(
304
+ edgesFragment != null,
305
+ 'usePrefetchableForwardPaginationFragment_EXPERIMENTAL: Expected the edge fragment to be defined, ' +
306
+ 'please make sure you have added `prefetchable_pagination: true` to `@connection`',
307
+ );
308
+
309
+ // Always try to keep `bufferSize` items in the buffer
310
+ // Or load the number of items that have been registred to show
311
+ useEffect(() => {
312
+ if (
313
+ // Check the ref to avoid infinite `loadMore`, when a `loadMore` has started,
314
+ // but `isLoadingMore` isn't updated
315
+ !isLoadingMoreRef.current &&
316
+ // Check the original `isLoadingMore` so when `loadMore` is called, the internal
317
+ // `loadMore` hook has been updated with the latest cursor
318
+ !isLoadingMore &&
319
+ !isRefetching &&
320
+ hasNext &&
321
+ (sourceSize - numInUse < bufferSize || numInUse > sourceSize)
322
+ ) {
323
+ const onComplete = prefetchingOnComplete;
324
+ loadMore(
325
+ Math.max(
326
+ bufferSize - Math.max(sourceSize - numInUse, 0),
327
+ numInUse - sourceSize,
328
+ minimalFetchSize,
329
+ ),
330
+ {
331
+ onComplete,
332
+ UNSTABLE_extraVariables:
333
+ typeof prefetchingUNSTABLE_extraVariables === 'function'
334
+ ? // $FlowFixMe[incompatible-call]
335
+ prefetchingUNSTABLE_extraVariables({
336
+ hasNext,
337
+ // $FlowFixMe[incompatible-call]
338
+ data: fragmentData,
339
+ getServerEdges: () => {
340
+ const selector = getSelector(edgesFragment, edgeKeys);
341
+ if (selector == null) {
342
+ // $FlowFixMe[incompatible-call]
343
+ return [];
344
+ }
345
+ invariant(
346
+ selector.kind === 'PluralReaderSelector',
347
+ 'Expected a plural selector',
348
+ );
349
+ // $FlowFixMe[incompatible-call]
350
+ return selector.selectors.map(
351
+ sel => environment.lookup(sel).data,
352
+ );
353
+ },
354
+ })
355
+ : prefetchingUNSTABLE_extraVariables,
356
+ },
357
+ );
358
+ }
359
+ }, [
360
+ hasNext,
361
+ bufferSize,
362
+ isRefetching,
363
+ loadMore,
364
+ numInUse,
365
+ prefetchingUNSTABLE_extraVariables,
366
+ prefetchingOnComplete,
367
+ sourceSize,
368
+ edgeKeys,
369
+ isLoadingMore,
370
+ minimalFetchSize,
371
+ environment,
372
+ edgesFragment,
373
+ ]);
374
+
375
+ const realNumInUse = Math.min(numInUse, sourceSize);
376
+
377
+ const derivedEdgeKeys: $ReadOnlyArray<mixed> = useMemo(
378
+ () => edgeKeys?.slice(0, realNumInUse) ?? [],
379
+ [edgeKeys, realNumInUse],
380
+ );
381
+
382
+ // $FlowExpectedError[incompatible-call] - we know derivedEdgeKeys are the correct keys
383
+ const edges: TEdgeData = useFragment(edgesFragment, derivedEdgeKeys);
384
+
385
+ const refetchPagination = useCallback(
386
+ (variables: TVariables, options?: Options) => {
387
+ disposeFetchNext();
388
+ setIsRefetching(true);
389
+ return refetch(variables, {
390
+ ...options,
391
+ onComplete: maybeError => {
392
+ // Need to be batched with the store update
393
+ const schedule = environment.getScheduler()?.schedule;
394
+ if (schedule) {
395
+ schedule(() => {
396
+ setIsRefetching(false);
397
+ setNumInUse(-1);
398
+ });
399
+ } else {
400
+ setIsRefetching(false);
401
+ setNumInUse(-1);
402
+ }
403
+ options?.onComplete?.(maybeError);
404
+ },
405
+ __environment: undefined,
406
+ });
407
+ },
408
+ [disposeFetchNext, environment, refetch],
409
+ );
410
+
411
+ if (__DEV__) {
412
+ // $FlowFixMe[react-rule-hook]
413
+ // $FlowFixMe[react-rule-hook-conditional]
414
+ useDebugValue({
415
+ fragment: fragmentNode.name,
416
+ data: fragmentData,
417
+ hasNext,
418
+ isLoadingNext: isLoadingMore,
419
+ });
420
+ }
421
+
422
+ return {
423
+ edges,
424
+ // $FlowFixMe[incompatible-return]
425
+ data: fragmentData,
426
+ loadNext: showMore,
427
+ hasNext: hasNext || sourceSize > numInUse,
428
+ // Only reflect `isLoadingMore` if the product depends on it, do not refelect
429
+ // `isLoaindgMore` state if it is for fufilling the buffer
430
+ isLoadingNext: isLoadingMore && numInUse > sourceSize,
431
+ refetch: refetchPagination,
432
+ };
433
+ }
434
+
435
+ module.exports = usePrefetchableForwardPaginationFragment_EXPERIMENTAL;
@@ -160,6 +160,7 @@ hook usePreloadedQuery<
160
160
  if (__DEV__) {
161
161
  // eslint-disable-next-line react-hooks/rules-of-hooks
162
162
  // $FlowFixMe[react-rule-hook]
163
+ // $FlowFixMe[react-rule-hook-conditional]
163
164
  useDebugValue({
164
165
  query: preloadedQuery.name,
165
166
  variables: preloadedQuery.variables,
@@ -46,7 +46,9 @@ export type UseQueryLoaderLoadQueryOptions = $ReadOnly<{
46
46
  export type NullQueryReference = {
47
47
  kind: 'NullQueryReference',
48
48
  };
49
- const initialNullQueryReferenceState = {kind: 'NullQueryReference'};
49
+ const initialNullQueryReferenceState: NullQueryReference = {
50
+ kind: 'NullQueryReference',
51
+ };
50
52
 
51
53
  function requestIsLiveQuery<
52
54
  TVariables: Variables,
@@ -119,12 +121,14 @@ hook useQueryLoader<TVariables: Variables, TData, TRawResponse: ?{...} = void>(
119
121
  ): UseQueryLoaderHookReturnType<TVariables, TData> {
120
122
  if (RelayFeatureFlags.ENABLE_ACTIVITY_COMPATIBILITY) {
121
123
  // $FlowFixMe[react-rule-hook] - the condition is static
124
+ // $FlowFixMe[react-rule-hook-conditional]
122
125
  return useQueryLoader_EXPERIMENTAL(
123
126
  preloadableRequest,
124
127
  initialQueryReference,
125
128
  );
126
129
  }
127
130
  // $FlowFixMe[react-rule-hook] - the condition is static
131
+ // $FlowFixMe[react-rule-hook-conditional]
128
132
  return useQueryLoader_CURRENT(preloadableRequest, initialQueryReference);
129
133
  }
130
134
 
@@ -35,7 +35,9 @@ const {
35
35
  } = require('react');
36
36
  const {getRequest} = require('relay-runtime');
37
37
 
38
- const initialNullQueryReferenceState = {kind: 'NullQueryReference'};
38
+ const initialNullQueryReferenceState: NullQueryReference = {
39
+ kind: 'NullQueryReference',
40
+ };
39
41
 
40
42
  function requestIsLiveQuery<
41
43
  TVariables: Variables,
@@ -85,6 +85,7 @@ hook useRefetchableFragment<
85
85
  if (__DEV__) {
86
86
  // eslint-disable-next-line react-hooks/rules-of-hooks
87
87
  // $FlowFixMe[react-rule-hook]
88
+ // $FlowFixMe[react-rule-hook-conditional]
88
89
  useDebugValue({fragment: fragmentNode.name, data: fragmentData});
89
90
  }
90
91
  // $FlowFixMe[incompatible-return]
@@ -160,7 +160,7 @@ function reducer(state: RefetchState, action: Action): RefetchState {
160
160
  }
161
161
  }
162
162
 
163
- hook useRefetchableFragmentNode<
163
+ hook useRefetchableFragmentInternal<
164
164
  TQuery: OperationType,
165
165
  TKey: ?{+$data?: mixed, ...},
166
166
  >(
@@ -582,7 +582,7 @@ if (__DEV__) {
582
582
  fragmentNode: ReaderFragment,
583
583
  componentDisplayName: string,
584
584
  ): void {
585
- if (previousIDAndTypename == null) {
585
+ if (previousIDAndTypename == null || refetchedFragmentRef == null) {
586
586
  return;
587
587
  }
588
588
  const {ID_KEY} = require('relay-runtime');
@@ -605,4 +605,4 @@ if (__DEV__) {
605
605
  };
606
606
  }
607
607
 
608
- module.exports = useRefetchableFragmentNode;
608
+ module.exports = useRefetchableFragmentInternal;
@@ -0,0 +1,21 @@
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
+ const ReactRelayLoggingContext = require('./../ReactRelayLoggingContext');
15
+ const {useContext} = require('react');
16
+
17
+ hook useRelayLoggingContext(): mixed | void {
18
+ return useContext(ReactRelayLoggingContext);
19
+ }
20
+
21
+ module.exports = useRelayLoggingContext;
@@ -26,6 +26,7 @@ hook useStaticFragmentNodeWarning(
26
26
  // cost of `useRef` in development mode to produce the warning.
27
27
  // eslint-disable-next-line react-hooks/rules-of-hooks
28
28
  // $FlowFixMe[react-rule-hook]
29
+ // $FlowFixMe[react-rule-hook-conditional]
29
30
  const initialPropRef = useUnsafeRef_DEPRECATED(fragmentNode.name);
30
31
  warning(
31
32
  // $FlowFixMe[react-rule-unsafe-ref]