react-relay 13.1.0 → 14.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 (69) hide show
  1. package/ReactRelayContext.js +1 -1
  2. package/ReactRelayFragmentContainer.js.flow +7 -4
  3. package/ReactRelayLocalQueryRenderer.js.flow +1 -1
  4. package/ReactRelayPaginationContainer.js.flow +13 -8
  5. package/ReactRelayQueryFetcher.js.flow +1 -0
  6. package/ReactRelayQueryRenderer.js.flow +7 -6
  7. package/ReactRelayRefetchContainer.js.flow +10 -3
  8. package/__flowtests__/__generated__/ReactRelayFragmentContainerFlowtest_viewer.graphql.js.flow +2 -2
  9. package/__flowtests__/__generated__/ReactRelayFragmentContainerFlowtest_viewer2.graphql.js.flow +2 -2
  10. package/__flowtests__/__generated__/ReactRelayPaginationContainerFlowtestQuery.graphql.js.flow +3 -3
  11. package/__flowtests__/__generated__/ReactRelayPaginationContainerFlowtest_viewer.graphql.js.flow +3 -3
  12. package/__flowtests__/__generated__/ReactRelayRefetchContainerFlowtestQuery.graphql.js.flow +3 -3
  13. package/__flowtests__/__generated__/ReactRelayRefetchContainerFlowtest_viewer.graphql.js.flow +3 -3
  14. package/__flowtests__/__generated__/RelayModernFlowtest_badref.graphql.js.flow +2 -2
  15. package/__flowtests__/__generated__/RelayModernFlowtest_notref.graphql.js.flow +2 -2
  16. package/__flowtests__/__generated__/RelayModernFlowtest_user.graphql.js.flow +2 -2
  17. package/__flowtests__/__generated__/RelayModernFlowtest_users.graphql.js.flow +2 -2
  18. package/buildReactRelayContainer.js.flow +2 -2
  19. package/hooks.js +1 -1
  20. package/index.js +1 -1
  21. package/jest-react/internalAct.js.flow +25 -9
  22. package/legacy.js +1 -1
  23. package/lib/ReactRelayQueryFetcher.js +1 -0
  24. package/lib/ReactRelayQueryRenderer.js +1 -2
  25. package/lib/jest-react/internalAct.js +24 -4
  26. package/lib/readContext.js +2 -1
  27. package/lib/relay-hooks/FragmentResource.js +62 -23
  28. package/lib/relay-hooks/HooksImplementation.js +29 -0
  29. package/lib/relay-hooks/MatchContainer.js +1 -0
  30. package/lib/relay-hooks/QueryResource.js +4 -166
  31. package/lib/relay-hooks/preloadQuery_DEPRECATED.js +7 -11
  32. package/lib/relay-hooks/react-cache/RelayReactCache.js +37 -0
  33. package/lib/relay-hooks/react-cache/getQueryResultOrFetchQuery_REACT_CACHE.js +344 -0
  34. package/lib/relay-hooks/react-cache/useFragmentInternal_REACT_CACHE.js +540 -0
  35. package/lib/relay-hooks/react-cache/useFragment_REACT_CACHE.js +51 -0
  36. package/lib/relay-hooks/react-cache/useLazyLoadQuery_REACT_CACHE.js +56 -0
  37. package/lib/relay-hooks/react-cache/usePreloadedQuery_REACT_CACHE.js +125 -0
  38. package/lib/relay-hooks/useFragment.js +15 -1
  39. package/lib/relay-hooks/useLazyLoadQuery.js +18 -2
  40. package/lib/relay-hooks/useMutation.js +4 -5
  41. package/lib/relay-hooks/usePreloadedQuery.js +18 -2
  42. package/package.json +3 -3
  43. package/react-relay-hooks.js +2 -2
  44. package/react-relay-hooks.min.js +2 -2
  45. package/react-relay-legacy.js +2 -2
  46. package/react-relay-legacy.min.js +2 -2
  47. package/react-relay.js +2 -2
  48. package/react-relay.min.js +2 -2
  49. package/readContext.js.flow +1 -0
  50. package/relay-hooks/FragmentResource.js.flow +72 -27
  51. package/relay-hooks/HooksImplementation.js.flow +45 -0
  52. package/relay-hooks/MatchContainer.js.flow +8 -1
  53. package/relay-hooks/QueryResource.js.flow +8 -203
  54. package/relay-hooks/__flowtests__/__generated__/useFragmentFlowtest_user.graphql.js.flow +2 -2
  55. package/relay-hooks/__flowtests__/__generated__/useFragmentFlowtest_users.graphql.js.flow +2 -2
  56. package/relay-hooks/loadQuery.js.flow +2 -1
  57. package/relay-hooks/preloadQuery_DEPRECATED.js.flow +7 -14
  58. package/relay-hooks/react-cache/RelayReactCache.js.flow +42 -0
  59. package/relay-hooks/react-cache/getQueryResultOrFetchQuery_REACT_CACHE.js.flow +424 -0
  60. package/relay-hooks/react-cache/useFragmentInternal_REACT_CACHE.js.flow +559 -0
  61. package/relay-hooks/react-cache/useFragment_REACT_CACHE.js.flow +74 -0
  62. package/relay-hooks/react-cache/useLazyLoadQuery_REACT_CACHE.js.flow +72 -0
  63. package/relay-hooks/react-cache/usePreloadedQuery_REACT_CACHE.js.flow +153 -0
  64. package/relay-hooks/useFragment.js.flow +17 -10
  65. package/relay-hooks/useLazyLoadQuery.js.flow +38 -3
  66. package/relay-hooks/useMutation.js.flow +3 -3
  67. package/relay-hooks/usePreloadedQuery.js.flow +30 -2
  68. package/relay-hooks/useRefetchableFragmentNode.js.flow +26 -11
  69. package/relay-hooks/useSubscription.js.flow +14 -8
@@ -32,7 +32,7 @@ import type {
32
32
  const LRUCache = require('./LRUCache');
33
33
  const SuspenseResource = require('./SuspenseResource');
34
34
  const invariant = require('invariant');
35
- const {RelayFeatureFlags, isPromise} = require('relay-runtime');
35
+ const {isPromise} = require('relay-runtime');
36
36
  const warning = require('warning');
37
37
 
38
38
  const CACHE_CAPACITY = 1000;
@@ -50,8 +50,6 @@ type QueryResourceCacheEntry = {|
50
50
  // from the incremental responses, so later we can choose how to handle errors
51
51
  // in the incremental payloads.
52
52
  processedPayloadsCount: number,
53
- getRetainCount(): number,
54
- getNetworkSubscription(): ?Subscription,
55
53
  setNetworkSubscription(?Subscription): void,
56
54
  getValue(): Error | Promise<void> | QueryResult,
57
55
  setValue(Error | Promise<void> | QueryResult): void,
@@ -125,39 +123,6 @@ function createCacheEntry(
125
123
  value: Error | Promise<void> | QueryResult,
126
124
  networkSubscription: ?Subscription,
127
125
  onDispose: QueryResourceCacheEntry => void,
128
- ): QueryResourceCacheEntry {
129
- // There should be no behavior difference between createCacheEntry_new and
130
- // createCacheEntry_old, and it doesn't directly relate to Client Edges.
131
- // It was just a refactoring that was needed for Client Edges but that
132
- // is behind the feature flag just in case there is any accidental breakage.
133
- if (RelayFeatureFlags.REFACTOR_SUSPENSE_RESOURCE) {
134
- return createCacheEntry_new(
135
- cacheIdentifier,
136
- operation,
137
- operationAvailability,
138
- value,
139
- networkSubscription,
140
- onDispose,
141
- );
142
- } else {
143
- return createCacheEntry_old(
144
- cacheIdentifier,
145
- operation,
146
- operationAvailability,
147
- value,
148
- networkSubscription,
149
- onDispose,
150
- );
151
- }
152
- }
153
-
154
- function createCacheEntry_new(
155
- cacheIdentifier: string,
156
- operation: OperationDescriptor,
157
- operationAvailability: ?OperationAvailability,
158
- value: Error | Promise<void> | QueryResult,
159
- networkSubscription: ?Subscription,
160
- onDispose: QueryResourceCacheEntry => void,
161
126
  ): QueryResourceCacheEntry {
162
127
  const isLiveQuery = operationIsLiveQuery(operation);
163
128
 
@@ -191,12 +156,6 @@ function createCacheEntry_new(
191
156
  setValue(val: QueryResult | Promise<void> | Error) {
192
157
  currentValue = val;
193
158
  },
194
- getRetainCount() {
195
- return suspenseResource.getRetainCount();
196
- },
197
- getNetworkSubscription() {
198
- return currentNetworkSubscription;
199
- },
200
159
  setNetworkSubscription(subscription: ?Subscription) {
201
160
  if (isLiveQuery && currentNetworkSubscription != null) {
202
161
  currentNetworkSubscription.unsubscribe();
@@ -217,153 +176,6 @@ function createCacheEntry_new(
217
176
  return cacheEntry;
218
177
  }
219
178
 
220
- const DATA_RETENTION_TIMEOUT = 5 * 60 * 1000;
221
- function createCacheEntry_old(
222
- cacheIdentifier: string,
223
- operation: OperationDescriptor,
224
- operationAvailability: ?OperationAvailability,
225
- value: Error | Promise<void> | QueryResult,
226
- networkSubscription: ?Subscription,
227
- onDispose: QueryResourceCacheEntry => void,
228
- ): QueryResourceCacheEntry {
229
- const isLiveQuery = operationIsLiveQuery(operation);
230
-
231
- let currentValue: Error | Promise<void> | QueryResult = value;
232
- let retainCount = 0;
233
- let retainDisposable: ?Disposable = null;
234
- let releaseTemporaryRetain: ?() => void = null;
235
- let currentNetworkSubscription: ?Subscription = networkSubscription;
236
-
237
- const retain = (environment: IEnvironment) => {
238
- retainCount++;
239
- if (retainCount === 1) {
240
- retainDisposable = environment.retain(operation);
241
- }
242
- return {
243
- dispose: () => {
244
- retainCount = Math.max(0, retainCount - 1);
245
- if (retainCount === 0) {
246
- invariant(
247
- retainDisposable != null,
248
- 'Relay: Expected disposable to release query to be defined.' +
249
- "If you're seeing this, this is likely a bug in Relay.",
250
- );
251
- retainDisposable.dispose();
252
- retainDisposable = null;
253
- }
254
- onDispose(cacheEntry);
255
- },
256
- };
257
- };
258
-
259
- const cacheEntry = {
260
- cacheIdentifier,
261
- id: nextID++,
262
- processedPayloadsCount: 0,
263
- operationAvailability,
264
- getValue() {
265
- return currentValue;
266
- },
267
- setValue(val: QueryResult | Promise<void> | Error) {
268
- currentValue = val;
269
- },
270
- getRetainCount() {
271
- return retainCount;
272
- },
273
- getNetworkSubscription() {
274
- return currentNetworkSubscription;
275
- },
276
- setNetworkSubscription(subscription: ?Subscription) {
277
- if (isLiveQuery && currentNetworkSubscription != null) {
278
- currentNetworkSubscription.unsubscribe();
279
- }
280
- currentNetworkSubscription = subscription;
281
- },
282
- temporaryRetain(environment: IEnvironment): Disposable {
283
- // NOTE: If we're executing in a server environment, there's no need
284
- // to create temporary retains, since the component will never commit.
285
- if (environment.isServer()) {
286
- return {dispose: () => {}};
287
- }
288
-
289
- // NOTE: temporaryRetain is called during the render phase. However,
290
- // given that we can't tell if this render will eventually commit or not,
291
- // we create a timer to autodispose of this retain in case the associated
292
- // component never commits.
293
- // If the component /does/ commit, permanentRetain will clear this timeout
294
- // and permanently retain the data.
295
- const disposable = retain(environment);
296
- let releaseQueryTimeout = null;
297
- const localReleaseTemporaryRetain = () => {
298
- clearTimeout(releaseQueryTimeout);
299
- releaseQueryTimeout = null;
300
- releaseTemporaryRetain = null;
301
- disposable.dispose();
302
- // Normally if this entry never commits, the request would've ended by the
303
- // time this timeout expires and the temporary retain is released. However,
304
- // we need to do this for live queries which remain open indefinitely.
305
- if (
306
- isLiveQuery &&
307
- retainCount <= 0 &&
308
- currentNetworkSubscription != null
309
- ) {
310
- currentNetworkSubscription.unsubscribe();
311
- }
312
- };
313
- releaseQueryTimeout = setTimeout(
314
- localReleaseTemporaryRetain,
315
- DATA_RETENTION_TIMEOUT,
316
- );
317
-
318
- // NOTE: Since temporaryRetain can be called multiple times, we release
319
- // the previous temporary retain after we re-establish a new one, since
320
- // we only ever need a single temporary retain until the permanent retain is
321
- // established.
322
- // temporaryRetain may be called multiple times by React during the render
323
- // phase, as well as multiple times by other query components that are
324
- // rendering the same query/variables.
325
- if (releaseTemporaryRetain != null) {
326
- releaseTemporaryRetain();
327
- }
328
- releaseTemporaryRetain = localReleaseTemporaryRetain;
329
-
330
- return {
331
- dispose: () => {
332
- releaseTemporaryRetain && releaseTemporaryRetain();
333
- },
334
- };
335
- },
336
- permanentRetain(environment: IEnvironment): Disposable {
337
- const disposable = retain(environment);
338
- if (releaseTemporaryRetain != null) {
339
- releaseTemporaryRetain();
340
- releaseTemporaryRetain = null;
341
- }
342
-
343
- return {
344
- dispose: () => {
345
- disposable.dispose();
346
- if (
347
- isLiveQuery &&
348
- retainCount <= 0 &&
349
- currentNetworkSubscription != null
350
- ) {
351
- currentNetworkSubscription.unsubscribe();
352
- }
353
- },
354
- };
355
- },
356
- releaseTemporaryRetain() {
357
- if (releaseTemporaryRetain != null) {
358
- releaseTemporaryRetain();
359
- releaseTemporaryRetain = null;
360
- }
361
- },
362
- };
363
-
364
- return cacheEntry;
365
- }
366
-
367
179
  class QueryResourceImpl {
368
180
  _environment: IEnvironment;
369
181
  _cache: QueryResourceCache;
@@ -532,15 +344,7 @@ class QueryResourceImpl {
532
344
  }
533
345
 
534
346
  _clearCacheEntry = (cacheEntry: QueryResourceCacheEntry): void => {
535
- // The new code does this retainCount <= 0 check within SuspenseResource
536
- // before calling _clearCacheEntry, whereas with the old code we do it here.
537
- if (RelayFeatureFlags.REFACTOR_SUSPENSE_RESOURCE) {
538
- this._cache.delete(cacheEntry.cacheIdentifier);
539
- } else {
540
- if (cacheEntry.getRetainCount() <= 0) {
541
- this._cache.delete(cacheEntry.cacheIdentifier);
542
- }
543
- }
347
+ this._cache.delete(cacheEntry.cacheIdentifier);
544
348
  };
545
349
 
546
350
  _getOrCreateCacheEntry(
@@ -588,7 +392,9 @@ class QueryResourceImpl {
588
392
 
589
393
  let shouldFetch;
590
394
  let shouldAllowRender;
591
- let resolveNetworkPromise = () => {};
395
+ // Different definitions for Promise in our repos can cause this variable
396
+ // to cause errors when synced elsewhere
397
+ let resolveNetworkPromise: $FlowFixMe = () => {};
592
398
  switch (fetchPolicy) {
593
399
  case 'store-only': {
594
400
  shouldFetch = false;
@@ -632,7 +438,7 @@ class QueryResourceImpl {
632
438
 
633
439
  if (shouldFetch) {
634
440
  const queryResult = getQueryResult(operation, cacheIdentifier);
635
- let networkSubscription;
441
+ let networkSubscription: ?Subscription;
636
442
  fetchObservable.subscribe({
637
443
  start: subscription => {
638
444
  networkSubscription = subscription;
@@ -693,10 +499,9 @@ class QueryResourceImpl {
693
499
  // To complete this task we need to have a way of precisely tracking suspendable points
694
500
  warning(
695
501
  false,
696
- 'QueryResource: An incremental payload for query `%` returned an error: `%`:`%`.',
502
+ 'QueryResource: An incremental payload for query `%s` returned an error: `%s`.',
697
503
  operation.fragment.node.name,
698
- error.message,
699
- error.stack,
504
+ String(error.message),
700
505
  );
701
506
  }
702
507
  resolveNetworkPromise();
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * Copyright (c) Meta Platforms, Inc. and affiliates.
3
- *
3
+ *
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
- * @generated SignedSource<<6bdf42be355b40305d9006059aa56d70>>
7
+ * @generated SignedSource<<8a8e68a3fde4da3f77546ac4952f2635>>
8
8
  * @flow
9
9
  * @lightSyntaxTransform
10
10
  * @nogrep
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * Copyright (c) Meta Platforms, Inc. and affiliates.
3
- *
3
+ *
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
- * @generated SignedSource<<22f34b875909574b411e656fc3e592db>>
7
+ * @generated SignedSource<<0b4a6e76a104111de9ddd4dd9abe667c>>
8
8
  * @flow
9
9
  * @lightSyntaxTransform
10
10
  * @nogrep
@@ -17,6 +17,7 @@ import type {
17
17
  PreloadedQueryInner,
18
18
  } from './EntryPointTypes.flow';
19
19
  import type {
20
+ ConcreteRequest,
20
21
  GraphQLResponse,
21
22
  GraphQLTaggedNode,
22
23
  IEnvironment,
@@ -236,7 +237,7 @@ function loadQuery<TQuery: OperationType, TEnvironmentProviderOptions>(
236
237
  }));
237
238
  };
238
239
 
239
- const checkAvailabilityAndExecute = concreteRequest => {
240
+ const checkAvailabilityAndExecute = (concreteRequest: ConcreteRequest) => {
240
241
  const operation = createOperationDescriptor(
241
242
  concreteRequest,
242
243
  variables,
@@ -115,20 +115,13 @@ function preloadQuery<TQuery: OperationType, TEnvironmentProviderOptions>(
115
115
  if (environment.isServer()) {
116
116
  return;
117
117
  }
118
- if (
119
- RelayFeatureFlags.DELAY_CLEANUP_OF_PENDING_PRELOAD_QUERIES ===
120
- true
121
- ) {
122
- setTimeout(() => {
123
- // Clear the cache entry after the default timeout
124
- // null-check for Flow
125
- if (queryEntry != null) {
126
- cleanup(pendingQueries, queryEntry);
127
- }
128
- }, DEFAULT_PREFETCH_TIMEOUT);
129
- } else {
130
- cleanup(pendingQueries, queryEntry);
131
- }
118
+ setTimeout(() => {
119
+ // Clear the cache entry after the default timeout
120
+ // null-check for Flow
121
+ if (queryEntry != null) {
122
+ cleanup(pendingQueries, queryEntry);
123
+ }
124
+ }, DEFAULT_PREFETCH_TIMEOUT);
132
125
  };
133
126
  })
134
127
  : null;
@@ -0,0 +1,42 @@
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
+ * @emails oncall+relay
9
+ * @format
10
+ */
11
+
12
+ // flowlint ambiguous-object-type:error
13
+
14
+ 'use strict';
15
+
16
+ const invariant = require('invariant');
17
+ // $FlowFixMe[prop-missing] These exist in experimental builds but aren't in React's types yet.
18
+ const {unstable_getCacheForType, unstable_getCacheSignal} = require('react');
19
+ const {RelayFeatureFlags} = require('relay-runtime');
20
+
21
+ function getCacheForType<T>(factory: () => T): T {
22
+ invariant(
23
+ typeof unstable_getCacheForType === 'function' &&
24
+ RelayFeatureFlags.USE_REACT_CACHE,
25
+ 'RelayReactCache.getCacheForType should only be called when the USE_REACT_CACHE feature flag is enabled and when on an experimental React build that supports it.',
26
+ );
27
+ return unstable_getCacheForType(factory);
28
+ }
29
+
30
+ function getCacheSignal(): AbortSignal {
31
+ invariant(
32
+ typeof unstable_getCacheSignal === 'function' &&
33
+ RelayFeatureFlags.USE_REACT_CACHE,
34
+ 'RelayReactCache.getCacheSignal should only be called when the USE_REACT_CACHE feature flag is enabled and when on an experimental React build that supports it.',
35
+ );
36
+ return unstable_getCacheSignal();
37
+ }
38
+
39
+ module.exports = {
40
+ getCacheForType,
41
+ getCacheSignal,
42
+ };