react-relay 13.1.0 → 14.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ };