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
@@ -14,6 +14,7 @@
14
14
  import type {QueryResult} from './QueryResource';
15
15
  import type {
16
16
  CacheConfig,
17
+ DataID,
17
18
  FetchPolicy,
18
19
  IEnvironment,
19
20
  ReaderFragment,
@@ -21,13 +22,11 @@ import type {
21
22
  SelectorData,
22
23
  Snapshot,
23
24
  } from 'relay-runtime';
24
- import type {
25
- MissingClientEdgeRequestInfo,
26
- MissingLiveResolverField,
27
- } from 'relay-runtime/store/RelayStoreTypes';
25
+ import type {MissingClientEdgeRequestInfo} from 'relay-runtime/store/RelayStoreTypes';
28
26
 
29
27
  const {getQueryResourceForEnvironment} = require('./QueryResource');
30
28
  const useRelayEnvironment = require('./useRelayEnvironment');
29
+ const useRelayLoggingContext = require('./useRelayLoggingContext');
31
30
  const invariant = require('invariant');
32
31
  const {useDebugValue, useEffect, useMemo, useRef, useState} = require('react');
33
32
  const {
@@ -101,13 +100,13 @@ function getMissingClientEdges(
101
100
 
102
101
  function getSuspendingLiveResolver(
103
102
  state: FragmentState,
104
- ): $ReadOnlyArray<MissingLiveResolverField> | null {
103
+ ): $ReadOnlyArray<DataID> | null {
105
104
  if (state.kind === 'bailout') {
106
105
  return null;
107
106
  } else if (state.kind === 'singular') {
108
107
  return state.snapshot.missingLiveResolverFields ?? null;
109
108
  } else {
110
- let missingFields: null | Array<MissingLiveResolverField> = null;
109
+ let missingFields: null | Array<DataID> = null;
111
110
  for (const snapshot of state.snapshots) {
112
111
  if (snapshot.missingLiveResolverFields) {
113
112
  missingFields = missingFields ?? [];
@@ -123,15 +122,21 @@ function getSuspendingLiveResolver(
123
122
  function handlePotentialSnapshotErrorsForState(
124
123
  environment: IEnvironment,
125
124
  state: FragmentState,
125
+ loggingContext: mixed | void,
126
126
  ): void {
127
127
  if (state.kind === 'singular') {
128
128
  handlePotentialSnapshotErrors(
129
129
  environment,
130
- state.snapshot.errorResponseFields,
130
+ state.snapshot.fieldErrors,
131
+ loggingContext,
131
132
  );
132
133
  } else if (state.kind === 'plural') {
133
134
  for (const snapshot of state.snapshots) {
134
- handlePotentialSnapshotErrors(environment, snapshot.errorResponseFields);
135
+ handlePotentialSnapshotErrors(
136
+ environment,
137
+ snapshot.fieldErrors,
138
+ loggingContext,
139
+ );
135
140
  }
136
141
  }
137
142
  }
@@ -167,7 +172,7 @@ function handleMissedUpdates(
167
172
  missingLiveResolverFields: currentSnapshot.missingLiveResolverFields,
168
173
  seenRecords: currentSnapshot.seenRecords,
169
174
  selector: currentSnapshot.selector,
170
- errorResponseFields: currentSnapshot.errorResponseFields,
175
+ fieldErrors: currentSnapshot.fieldErrors,
171
176
  };
172
177
  return [
173
178
  updatedData !== state.snapshot.data,
@@ -193,7 +198,7 @@ function handleMissedUpdates(
193
198
  missingLiveResolverFields: currentSnapshot.missingLiveResolverFields,
194
199
  seenRecords: currentSnapshot.seenRecords,
195
200
  selector: currentSnapshot.selector,
196
- errorResponseFields: currentSnapshot.errorResponseFields,
201
+ fieldErrors: currentSnapshot.fieldErrors,
197
202
  };
198
203
  if (updatedData !== snapshot.data) {
199
204
  didMissUpdates = true;
@@ -433,6 +438,12 @@ hook useFragmentInternal_EXPERIMENTAL(
433
438
  );
434
439
 
435
440
  const environment = useRelayEnvironment();
441
+ let loggerContext;
442
+ if (RelayFeatureFlags.ENABLE_UI_CONTEXT_ON_RELAY_LOGGER) {
443
+ // $FlowFixMe[react-rule-hook] - the condition is static
444
+ // $FlowFixMe[react-rule-hook-conditional]
445
+ loggerContext = useRelayLoggingContext();
446
+ }
436
447
  const [_state, setState] = useState<FragmentState>(() =>
437
448
  getFragmentState(environment, fragmentSelector),
438
449
  );
@@ -471,6 +482,7 @@ hook useFragmentInternal_EXPERIMENTAL(
471
482
  // always or never run for a given invocation of this hook.
472
483
  // eslint-disable-next-line react-hooks/rules-of-hooks
473
484
  // $FlowFixMe[react-rule-hook]
485
+ // $FlowFixMe[react-rule-hook-conditional]
474
486
  const [clientEdgeQueries, activeRequestPromises] = useMemo(() => {
475
487
  const missingClientEdges = getMissingClientEdges(state);
476
488
  // eslint-disable-next-line no-shadow
@@ -502,6 +514,7 @@ hook useFragmentInternal_EXPERIMENTAL(
502
514
  // See above note
503
515
  // eslint-disable-next-line react-hooks/rules-of-hooks
504
516
  // $FlowFixMe[react-rule-hook]
517
+ // $FlowFixMe[react-rule-hook-conditional]
505
518
  useEffect(() => {
506
519
  const QueryResource = getQueryResourceForEnvironment(environment);
507
520
  if (clientEdgeQueries?.length) {
@@ -523,7 +536,7 @@ hook useFragmentInternal_EXPERIMENTAL(
523
536
  const suspendingLiveResolvers = getSuspendingLiveResolver(state);
524
537
  if (suspendingLiveResolvers != null && suspendingLiveResolvers.length > 0) {
525
538
  throw Promise.all(
526
- suspendingLiveResolvers.map(({liveStateID}) => {
539
+ suspendingLiveResolvers.map(liveStateID => {
527
540
  // $FlowFixMe[prop-missing] This is expected to be a RelayModernStore
528
541
  return environment.getStore().getLiveResolverPromise(liveStateID);
529
542
  }),
@@ -558,7 +571,7 @@ hook useFragmentInternal_EXPERIMENTAL(
558
571
 
559
572
  // Report required fields only if we're not suspending, since that means
560
573
  // they're missing even though we are out of options for possibly fetching them:
561
- handlePotentialSnapshotErrorsForState(environment, state);
574
+ handlePotentialSnapshotErrorsForState(environment, state, loggerContext);
562
575
 
563
576
  // We emulate CRUD effects using a ref and two effects:
564
577
  // - The ref tracks the current state (including updates from the subscription)
@@ -579,6 +592,7 @@ hook useFragmentInternal_EXPERIMENTAL(
579
592
  selector: ?ReaderSelector,
580
593
  environment: IEnvironment,
581
594
  } | null>(null);
595
+ // $FlowFixMe[react-rule-hook] - the condition is static
582
596
  useEffect(() => {
583
597
  const storeSubscription = storeSubscriptionRef.current;
584
598
  if (storeSubscription != null) {
@@ -631,6 +645,7 @@ hook useFragmentInternal_EXPERIMENTAL(
631
645
  environment: state.environment,
632
646
  };
633
647
  }, [state]);
648
+ // $FlowFixMe[react-rule-hook] - the condition is static
634
649
  useEffect(() => {
635
650
  if (storeSubscriptionRef.current == null && state.kind !== 'bailout') {
636
651
  const dispose = subscribeToSnapshot(state.environment, state, setState);
@@ -658,6 +673,7 @@ hook useFragmentInternal_EXPERIMENTAL(
658
673
  const fragmentRefIsNullish = fragmentRef == null; // for less sensitive memoization
659
674
  // eslint-disable-next-line react-hooks/rules-of-hooks
660
675
  // $FlowFixMe[react-rule-hook]
676
+ // $FlowFixMe[react-rule-hook-conditional]
661
677
  data = useMemo(() => {
662
678
  if (state.kind === 'bailout') {
663
679
  // Bailout state can happen if the fragmentRef is a plural array that is empty or has no
@@ -709,6 +725,7 @@ hook useFragmentInternal_EXPERIMENTAL(
709
725
  if (__DEV__) {
710
726
  // eslint-disable-next-line react-hooks/rules-of-hooks
711
727
  // $FlowFixMe[react-rule-hook]
728
+ // $FlowFixMe[react-rule-hook-conditional]
712
729
  useDebugValue({fragment: fragmentNode.name, data});
713
730
  }
714
731
 
@@ -32,23 +32,23 @@ const {
32
32
  export type UseLazyLoadQueryHookType = hook <TVariables: Variables, TData>(
33
33
  gqlQuery: Query<TVariables, TData>,
34
34
  variables: TVariables,
35
- options?: {
35
+ options?: $ReadOnly<{
36
36
  fetchKey?: string | number,
37
37
  fetchPolicy?: FetchPolicy,
38
38
  networkCacheConfig?: CacheConfig,
39
39
  UNSTABLE_renderPolicy?: RenderPolicy,
40
- },
40
+ }>,
41
41
  ) => TData;
42
42
 
43
43
  hook useLazyLoadQuery<TVariables: Variables, TData>(
44
44
  gqlQuery: Query<TVariables, TData>,
45
45
  variables: TVariables,
46
- options?: {
46
+ options?: $ReadOnly<{
47
47
  fetchKey?: string | number,
48
48
  fetchPolicy?: FetchPolicy,
49
49
  networkCacheConfig?: CacheConfig,
50
50
  UNSTABLE_renderPolicy?: RenderPolicy,
51
- },
51
+ }>,
52
52
  ): TData {
53
53
  const environment = useRelayEnvironment();
54
54
 
@@ -67,9 +67,11 @@ hook useLoadMoreFunction<TVariables: Variables>(
67
67
  ): [LoadMoreFn<TVariables>, boolean, () => void] {
68
68
  if (RelayFeatureFlags.ENABLE_ACTIVITY_COMPATIBILITY) {
69
69
  // $FlowFixMe[react-rule-hook] - the condition is static
70
+ // $FlowFixMe[react-rule-hook-conditional]
70
71
  return useLoadMoreFunction_EXPERIMENTAL(args);
71
72
  }
72
73
  // $FlowFixMe[react-rule-hook] - the condition is static
74
+ // $FlowFixMe[react-rule-hook-conditional]
73
75
  return useLoadMoreFunction_CURRENT(args);
74
76
  }
75
77
 
@@ -138,6 +140,8 @@ hook useLoadMoreFunction_CURRENT<TVariables: Variables>(
138
140
  };
139
141
  }, [disposeFetch]);
140
142
 
143
+ const isRequestInvalid = fragmentData == null || isParentQueryActive;
144
+
141
145
  const loadMore = useCallback(
142
146
  (
143
147
  count: number,
@@ -166,11 +170,8 @@ hook useLoadMoreFunction_CURRENT<TVariables: Variables>(
166
170
  }
167
171
 
168
172
  const fragmentSelector = getSelector(fragmentNode, fragmentRef);
169
- if (
170
- isFetchingRef.current === true ||
171
- fragmentData == null ||
172
- isParentQueryActive
173
- ) {
173
+
174
+ if (isFetchingRef.current === true || isRequestInvalid) {
174
175
  if (fragmentSelector == null) {
175
176
  warning(
176
177
  false,
@@ -271,8 +272,7 @@ hook useLoadMoreFunction_CURRENT<TVariables: Variables>(
271
272
  disposeFetch,
272
273
  completeFetch,
273
274
  isFetchingRef,
274
- isParentQueryActive,
275
- fragmentData,
275
+ isRequestInvalid,
276
276
  fragmentNode.name,
277
277
  fragmentRef,
278
278
  componentDisplayName,
@@ -135,6 +135,8 @@ hook useLoadMoreFunction_EXPERIMENTAL<TVariables: Variables>(
135
135
  connectionPathInFragmentData,
136
136
  );
137
137
 
138
+ const isRequestInvalid = fragmentData == null || isParentQueryActive;
139
+
138
140
  const isMountedRef = useIsMountedRef();
139
141
  const loadMore = useCallback(
140
142
  (
@@ -164,11 +166,8 @@ hook useLoadMoreFunction_EXPERIMENTAL<TVariables: Variables>(
164
166
  }
165
167
 
166
168
  const fragmentSelector = getSelector(fragmentNode, fragmentRef);
167
- if (
168
- fetchStatusRef.current.kind === 'fetching' ||
169
- fragmentData == null ||
170
- isParentQueryActive
171
- ) {
169
+
170
+ if (fetchStatusRef.current.kind === 'fetching' || isRequestInvalid) {
172
171
  if (fragmentSelector == null) {
173
172
  warning(
174
173
  false,
@@ -267,8 +266,7 @@ hook useLoadMoreFunction_EXPERIMENTAL<TVariables: Variables>(
267
266
  identifierValue,
268
267
  direction,
269
268
  cursor,
270
- isParentQueryActive,
271
- fragmentData,
269
+ isRequestInvalid,
272
270
  fragmentNode.name,
273
271
  fragmentRef,
274
272
  componentDisplayName,
@@ -16,8 +16,6 @@ import type {Options} from './useRefetchableFragmentInternal';
16
16
  import type {
17
17
  Disposable,
18
18
  FragmentType,
19
- GraphQLResponse,
20
- Observer,
21
19
  RefetchableFragment,
22
20
  Variables,
23
21
  } from 'relay-runtime';
@@ -28,6 +26,7 @@ const useRelayEnvironment = require('./useRelayEnvironment');
28
26
  const useStaticFragmentNodeWarning = require('./useStaticFragmentNodeWarning');
29
27
  const {useCallback, useDebugValue, useState} = require('react');
30
28
  const {
29
+ RelayFeatureFlags,
31
30
  getFragment,
32
31
  getFragmentIdentifier,
33
32
  getPaginationMetadata,
@@ -145,6 +144,7 @@ hook usePaginationFragment<
145
144
  if (__DEV__) {
146
145
  // eslint-disable-next-line react-hooks/rules-of-hooks
147
146
  // $FlowFixMe[react-rule-hook]
147
+ // $FlowFixMe[react-rule-hook-conditional]
148
148
  useDebugValue({
149
149
  fragment: fragmentNode.name,
150
150
  data: fragmentData,
@@ -168,14 +168,7 @@ hook usePaginationFragment<
168
168
  }
169
169
 
170
170
  hook useLoadMore<TVariables: Variables>(
171
- args: $Diff<
172
- UseLoadMoreFunctionArgs,
173
- {
174
- observer: Observer<GraphQLResponse>,
175
- onReset: () => void,
176
- ...
177
- },
178
- >,
171
+ args: Omit<UseLoadMoreFunctionArgs, 'observer' | 'onReset'>,
179
172
  ): [LoadMoreFn<TVariables>, boolean, boolean, () => void] {
180
173
  const environment = useRelayEnvironment();
181
174
  const [isLoadingMore, reallySetIsLoadingMore] = useState(false);
@@ -196,6 +189,9 @@ hook useLoadMore<TVariables: Variables>(
196
189
  start: () => setIsLoadingMore(true),
197
190
  complete: () => setIsLoadingMore(false),
198
191
  error: () => setIsLoadingMore(false),
192
+ unsubscribe: RelayFeatureFlags.ENABLE_USE_PAGINATION_IS_LOADING_FIX
193
+ ? () => setIsLoadingMore(false)
194
+ : undefined,
199
195
  };
200
196
  const handleReset = () => setIsLoadingMore(false);
201
197
  const [loadMore, hasMore, disposeFetch] = useLoadMoreFunction<TVariables>({