react-relay 13.0.3 → 13.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. package/ReactRelayContext.js +1 -1
  2. package/ReactRelayLocalQueryRenderer.js.flow +1 -1
  3. package/ReactRelayQueryRenderer.js.flow +1 -4
  4. package/__flowtests__/__generated__/ReactRelayFragmentContainerFlowtest_viewer.graphql.js.flow +1 -3
  5. package/__flowtests__/__generated__/ReactRelayFragmentContainerFlowtest_viewer2.graphql.js.flow +1 -3
  6. package/__flowtests__/__generated__/ReactRelayPaginationContainerFlowtestQuery.graphql.js.flow +2 -4
  7. package/__flowtests__/__generated__/ReactRelayPaginationContainerFlowtest_viewer.graphql.js.flow +1 -3
  8. package/__flowtests__/__generated__/ReactRelayRefetchContainerFlowtestQuery.graphql.js.flow +2 -4
  9. package/__flowtests__/__generated__/ReactRelayRefetchContainerFlowtest_viewer.graphql.js.flow +1 -3
  10. package/__flowtests__/__generated__/RelayModernFlowtest_badref.graphql.js.flow +1 -3
  11. package/__flowtests__/__generated__/RelayModernFlowtest_notref.graphql.js.flow +1 -3
  12. package/__flowtests__/__generated__/RelayModernFlowtest_user.graphql.js.flow +1 -3
  13. package/__flowtests__/__generated__/RelayModernFlowtest_users.graphql.js.flow +1 -3
  14. package/hooks.js +1 -1
  15. package/index.js +1 -1
  16. package/jest-react/internalAct.js.flow +25 -9
  17. package/legacy.js +1 -1
  18. package/lib/ReactRelayQueryRenderer.js +1 -1
  19. package/lib/jest-react/internalAct.js +24 -4
  20. package/lib/relay-hooks/FragmentResource.js +10 -13
  21. package/lib/relay-hooks/QueryResource.js +2 -165
  22. package/lib/relay-hooks/preloadQuery_DEPRECATED.js +7 -11
  23. package/lib/relay-hooks/react-cache/RelayReactCache.js +37 -0
  24. package/lib/relay-hooks/react-cache/getQueryResultOrFetchQuery_REACT_CACHE.js +197 -0
  25. package/lib/relay-hooks/react-cache/useFragmentInternal_REACT_CACHE.js +395 -0
  26. package/lib/relay-hooks/react-cache/useLazyLoadQuery_REACT_CACHE.js +45 -0
  27. package/package.json +3 -3
  28. package/react-relay-hooks.js +2 -2
  29. package/react-relay-hooks.min.js +2 -2
  30. package/react-relay-legacy.js +2 -2
  31. package/react-relay-legacy.min.js +2 -2
  32. package/react-relay.js +2 -2
  33. package/react-relay.min.js +2 -2
  34. package/relay-hooks/FragmentResource.js.flow +17 -18
  35. package/relay-hooks/QueryResource.js.flow +4 -201
  36. package/relay-hooks/__flowtests__/__generated__/useFragmentFlowtest_user.graphql.js.flow +1 -3
  37. package/relay-hooks/__flowtests__/__generated__/useFragmentFlowtest_users.graphql.js.flow +1 -3
  38. package/relay-hooks/preloadQuery_DEPRECATED.js.flow +7 -14
  39. package/relay-hooks/react-cache/RelayReactCache.js.flow +42 -0
  40. package/relay-hooks/react-cache/getQueryResultOrFetchQuery_REACT_CACHE.js.flow +243 -0
  41. package/relay-hooks/react-cache/useFragmentInternal_REACT_CACHE.js.flow +416 -0
  42. package/relay-hooks/react-cache/useLazyLoadQuery_REACT_CACHE.js.flow +66 -0
@@ -24,7 +24,6 @@ var SuspenseResource = require('./SuspenseResource');
24
24
  var invariant = require('invariant');
25
25
 
26
26
  var _require = require('relay-runtime'),
27
- RelayFeatureFlags = _require.RelayFeatureFlags,
28
27
  isPromise = _require.isPromise;
29
28
 
30
29
  var warning = require("fbjs/lib/warning");
@@ -66,18 +65,6 @@ function getQueryResult(operation, cacheIdentifier) {
66
65
  var nextID = 200000;
67
66
 
68
67
  function createCacheEntry(cacheIdentifier, operation, operationAvailability, value, networkSubscription, onDispose) {
69
- // There should be no behavior difference between createCacheEntry_new and
70
- // createCacheEntry_old, and it doesn't directly relate to Client Edges.
71
- // It was just a refactoring that was needed for Client Edges but that
72
- // is behind the feature flag just in case there is any accidental breakage.
73
- if (RelayFeatureFlags.REFACTOR_SUSPENSE_RESOURCE) {
74
- return createCacheEntry_new(cacheIdentifier, operation, operationAvailability, value, networkSubscription, onDispose);
75
- } else {
76
- return createCacheEntry_old(cacheIdentifier, operation, operationAvailability, value, networkSubscription, onDispose);
77
- }
78
- }
79
-
80
- function createCacheEntry_new(cacheIdentifier, operation, operationAvailability, value, networkSubscription, onDispose) {
81
68
  var isLiveQuery = operationIsLiveQuery(operation);
82
69
  var currentValue = value;
83
70
  var currentNetworkSubscription = networkSubscription;
@@ -108,12 +95,6 @@ function createCacheEntry_new(cacheIdentifier, operation, operationAvailability,
108
95
  setValue: function setValue(val) {
109
96
  currentValue = val;
110
97
  },
111
- getRetainCount: function getRetainCount() {
112
- return suspenseResource.getRetainCount();
113
- },
114
- getNetworkSubscription: function getNetworkSubscription() {
115
- return currentNetworkSubscription;
116
- },
117
98
  setNetworkSubscription: function setNetworkSubscription(subscription) {
118
99
  if (isLiveQuery && currentNetworkSubscription != null) {
119
100
  currentNetworkSubscription.unsubscribe();
@@ -134,156 +115,12 @@ function createCacheEntry_new(cacheIdentifier, operation, operationAvailability,
134
115
  return cacheEntry;
135
116
  }
136
117
 
137
- var DATA_RETENTION_TIMEOUT = 5 * 60 * 1000;
138
-
139
- function createCacheEntry_old(cacheIdentifier, operation, operationAvailability, value, networkSubscription, onDispose) {
140
- var isLiveQuery = operationIsLiveQuery(operation);
141
- var currentValue = value;
142
- var retainCount = 0;
143
- var retainDisposable = null;
144
- var _releaseTemporaryRetain = null;
145
- var currentNetworkSubscription = networkSubscription;
146
-
147
- var retain = function retain(environment) {
148
- retainCount++;
149
-
150
- if (retainCount === 1) {
151
- retainDisposable = environment.retain(operation);
152
- }
153
-
154
- return {
155
- dispose: function dispose() {
156
- retainCount = Math.max(0, retainCount - 1);
157
-
158
- if (retainCount === 0) {
159
- !(retainDisposable != null) ? process.env.NODE_ENV !== "production" ? invariant(false, 'Relay: Expected disposable to release query to be defined.' + "If you're seeing this, this is likely a bug in Relay.") : invariant(false) : void 0;
160
- retainDisposable.dispose();
161
- retainDisposable = null;
162
- }
163
-
164
- onDispose(cacheEntry);
165
- }
166
- };
167
- };
168
-
169
- var cacheEntry = {
170
- cacheIdentifier: cacheIdentifier,
171
- id: nextID++,
172
- processedPayloadsCount: 0,
173
- operationAvailability: operationAvailability,
174
- getValue: function getValue() {
175
- return currentValue;
176
- },
177
- setValue: function setValue(val) {
178
- currentValue = val;
179
- },
180
- getRetainCount: function getRetainCount() {
181
- return retainCount;
182
- },
183
- getNetworkSubscription: function getNetworkSubscription() {
184
- return currentNetworkSubscription;
185
- },
186
- setNetworkSubscription: function setNetworkSubscription(subscription) {
187
- if (isLiveQuery && currentNetworkSubscription != null) {
188
- currentNetworkSubscription.unsubscribe();
189
- }
190
-
191
- currentNetworkSubscription = subscription;
192
- },
193
- temporaryRetain: function temporaryRetain(environment) {
194
- // NOTE: If we're executing in a server environment, there's no need
195
- // to create temporary retains, since the component will never commit.
196
- if (environment.isServer()) {
197
- return {
198
- dispose: function dispose() {}
199
- };
200
- } // NOTE: temporaryRetain is called during the render phase. However,
201
- // given that we can't tell if this render will eventually commit or not,
202
- // we create a timer to autodispose of this retain in case the associated
203
- // component never commits.
204
- // If the component /does/ commit, permanentRetain will clear this timeout
205
- // and permanently retain the data.
206
-
207
-
208
- var disposable = retain(environment);
209
- var releaseQueryTimeout = null;
210
-
211
- var localReleaseTemporaryRetain = function localReleaseTemporaryRetain() {
212
- clearTimeout(releaseQueryTimeout);
213
- releaseQueryTimeout = null;
214
- _releaseTemporaryRetain = null;
215
- disposable.dispose(); // Normally if this entry never commits, the request would've ended by the
216
- // time this timeout expires and the temporary retain is released. However,
217
- // we need to do this for live queries which remain open indefinitely.
218
-
219
- if (isLiveQuery && retainCount <= 0 && currentNetworkSubscription != null) {
220
- currentNetworkSubscription.unsubscribe();
221
- }
222
- };
223
-
224
- releaseQueryTimeout = setTimeout(localReleaseTemporaryRetain, DATA_RETENTION_TIMEOUT); // NOTE: Since temporaryRetain can be called multiple times, we release
225
- // the previous temporary retain after we re-establish a new one, since
226
- // we only ever need a single temporary retain until the permanent retain is
227
- // established.
228
- // temporaryRetain may be called multiple times by React during the render
229
- // phase, as well as multiple times by other query components that are
230
- // rendering the same query/variables.
231
-
232
- if (_releaseTemporaryRetain != null) {
233
- _releaseTemporaryRetain();
234
- }
235
-
236
- _releaseTemporaryRetain = localReleaseTemporaryRetain;
237
- return {
238
- dispose: function dispose() {
239
- _releaseTemporaryRetain && _releaseTemporaryRetain();
240
- }
241
- };
242
- },
243
- permanentRetain: function permanentRetain(environment) {
244
- var disposable = retain(environment);
245
-
246
- if (_releaseTemporaryRetain != null) {
247
- _releaseTemporaryRetain();
248
-
249
- _releaseTemporaryRetain = null;
250
- }
251
-
252
- return {
253
- dispose: function dispose() {
254
- disposable.dispose();
255
-
256
- if (isLiveQuery && retainCount <= 0 && currentNetworkSubscription != null) {
257
- currentNetworkSubscription.unsubscribe();
258
- }
259
- }
260
- };
261
- },
262
- releaseTemporaryRetain: function releaseTemporaryRetain() {
263
- if (_releaseTemporaryRetain != null) {
264
- _releaseTemporaryRetain();
265
-
266
- _releaseTemporaryRetain = null;
267
- }
268
- }
269
- };
270
- return cacheEntry;
271
- }
272
-
273
118
  var QueryResourceImpl = /*#__PURE__*/function () {
274
119
  function QueryResourceImpl(environment) {
275
120
  var _this = this;
276
121
 
277
122
  (0, _defineProperty2["default"])(this, "_clearCacheEntry", function (cacheEntry) {
278
- // The new code does this retainCount <= 0 check within SuspenseResource
279
- // before calling _clearCacheEntry, whereas with the old code we do it here.
280
- if (RelayFeatureFlags.REFACTOR_SUSPENSE_RESOURCE) {
281
- _this._cache["delete"](cacheEntry.cacheIdentifier);
282
- } else {
283
- if (cacheEntry.getRetainCount() <= 0) {
284
- _this._cache["delete"](cacheEntry.cacheIdentifier);
285
- }
286
- }
123
+ _this._cache["delete"](cacheEntry.cacheIdentifier);
287
124
  });
288
125
  this._environment = environment;
289
126
  this._cache = LRUCache.create(CACHE_CAPACITY);
@@ -529,7 +366,7 @@ var QueryResourceImpl = /*#__PURE__*/function () {
529
366
  } else {
530
367
  // TODO:T92030819 Remove this warning and actually throw the network error
531
368
  // To complete this task we need to have a way of precisely tracking suspendable points
532
- process.env.NODE_ENV !== "production" ? warning(false, 'QueryResource: An incremental payload for query `%` returned an error: `%`:`%`.', operation.fragment.node.name, _error.message, _error.stack) : void 0;
369
+ process.env.NODE_ENV !== "production" ? warning(false, 'QueryResource: An incremental payload for query `%s` returned an error: `%s`.', operation.fragment.node.name, String(_error.message)) : void 0;
533
370
  }
534
371
 
535
372
  resolveNetworkPromise();
@@ -64,17 +64,13 @@ function preloadQuery(environment, preloadableRequest, variables, options, envir
64
64
  return;
65
65
  }
66
66
 
67
- if (RelayFeatureFlags.DELAY_CLEANUP_OF_PENDING_PRELOAD_QUERIES === true) {
68
- setTimeout(function () {
69
- // Clear the cache entry after the default timeout
70
- // null-check for Flow
71
- if (queryEntry != null) {
72
- cleanup(pendingQueries, queryEntry);
73
- }
74
- }, DEFAULT_PREFETCH_TIMEOUT);
75
- } else {
76
- cleanup(pendingQueries, queryEntry);
77
- }
67
+ setTimeout(function () {
68
+ // Clear the cache entry after the default timeout
69
+ // null-check for Flow
70
+ if (queryEntry != null) {
71
+ cleanup(pendingQueries, queryEntry);
72
+ }
73
+ }, DEFAULT_PREFETCH_TIMEOUT);
78
74
  };
79
75
  }) : null;
80
76
  return {
@@ -0,0 +1,37 @@
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
+ *
8
+ * @emails oncall+relay
9
+ * @format
10
+ */
11
+ // flowlint ambiguous-object-type:error
12
+ 'use strict';
13
+
14
+ var invariant = require('invariant'); // $FlowFixMe[prop-missing] These exist in experimental builds but aren't in React's types yet.
15
+
16
+
17
+ var _require = require('react'),
18
+ unstable_getCacheForType = _require.unstable_getCacheForType,
19
+ unstable_getCacheSignal = _require.unstable_getCacheSignal;
20
+
21
+ var _require2 = require('relay-runtime'),
22
+ RelayFeatureFlags = _require2.RelayFeatureFlags;
23
+
24
+ function getCacheForType(factory) {
25
+ !(typeof unstable_getCacheForType === 'function' && RelayFeatureFlags.USE_REACT_CACHE) ? process.env.NODE_ENV !== "production" ? invariant(false, '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.') : invariant(false) : void 0;
26
+ return unstable_getCacheForType(factory);
27
+ }
28
+
29
+ function getCacheSignal() {
30
+ !(typeof unstable_getCacheSignal === 'function' && RelayFeatureFlags.USE_REACT_CACHE) ? process.env.NODE_ENV !== "production" ? invariant(false, '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.') : invariant(false) : void 0;
31
+ return unstable_getCacheSignal();
32
+ }
33
+
34
+ module.exports = {
35
+ getCacheForType: getCacheForType,
36
+ getCacheSignal: getCacheSignal
37
+ };
@@ -0,0 +1,197 @@
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
+ *
8
+ * @emails oncall+relay
9
+ * @format
10
+ */
11
+ // flowlint ambiguous-object-type:error
12
+ 'use strict';
13
+
14
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
15
+
16
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
17
+
18
+ var _require = require('./RelayReactCache'),
19
+ getCacheForType = _require.getCacheForType,
20
+ getCacheSignal = _require.getCacheSignal;
21
+
22
+ var invariant = require('invariant');
23
+
24
+ var _require2 = require('relay-runtime'),
25
+ fetchQueryInternal = _require2.__internal.fetchQuery;
26
+
27
+ var warning = require("fbjs/lib/warning");
28
+
29
+ var DEFAULT_FETCH_POLICY = 'store-or-network';
30
+
31
+ function createQueryCache() {
32
+ return new Map();
33
+ }
34
+
35
+ function getQueryCacheKey(operation, fetchPolicy, renderPolicy) {
36
+ var cacheIdentifier = "".concat(fetchPolicy, "-").concat(renderPolicy, "-").concat(operation.request.identifier);
37
+ return cacheIdentifier;
38
+ }
39
+
40
+ function constructQueryResult(operation) {
41
+ var rootFragmentRef = {
42
+ __id: operation.fragment.dataID,
43
+ __fragments: (0, _defineProperty2["default"])({}, operation.fragment.node.name, operation.request.variables),
44
+ __fragmentOwner: operation.request
45
+ };
46
+ return {
47
+ fragmentNode: operation.request.node.fragment,
48
+ fragmentRef: rootFragmentRef
49
+ };
50
+ }
51
+
52
+ function getQueryResultOrFetchQuery_REACT_CACHE(environment, queryOperationDescriptor) {
53
+ var fetchPolicy = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : DEFAULT_FETCH_POLICY;
54
+ var maybeRenderPolicy = arguments.length > 3 ? arguments[3] : undefined;
55
+ var renderPolicy = maybeRenderPolicy !== null && maybeRenderPolicy !== void 0 ? maybeRenderPolicy : environment.UNSTABLE_getDefaultRenderPolicy();
56
+ var cache = getCacheForType(createQueryCache);
57
+ var cacheKey = getQueryCacheKey(queryOperationDescriptor, fetchPolicy, renderPolicy);
58
+ var entry = cache.get(cacheKey);
59
+
60
+ if (entry === undefined) {
61
+ // Initiate a query to fetch the data if needed:
62
+ entry = onCacheMiss(environment, queryOperationDescriptor, fetchPolicy, renderPolicy, function (newCacheEntry) {
63
+ cache.set(cacheKey, newCacheEntry);
64
+ });
65
+ cache.set(cacheKey, entry); // Since this is the first time rendering, retain the query. React will
66
+ // trigger the abort signal when this cache entry is no longer needed.
67
+
68
+ var retention = environment.retain(queryOperationDescriptor);
69
+ var abortSignal = getCacheSignal();
70
+ abortSignal.addEventListener('abort', function () {
71
+ retention.dispose();
72
+ cache["delete"](cacheKey);
73
+ }, {
74
+ once: true
75
+ });
76
+ }
77
+
78
+ switch (entry.status) {
79
+ case 'pending':
80
+ throw entry.promise;
81
+
82
+ case 'rejected':
83
+ throw entry.error;
84
+
85
+ case 'resolved':
86
+ return entry.result;
87
+ }
88
+
89
+ !false ? process.env.NODE_ENV !== "production" ? invariant(false, 'switch statement should be exhaustive') : invariant(false) : void 0;
90
+ }
91
+
92
+ function onCacheMiss(environment, operation, fetchPolicy, renderPolicy, updateCache) {
93
+ // NB: Besides checking if the data is available, calling `check` will write missing
94
+ // data to the store using any missing data handlers specified in the environment.
95
+ var queryAvailability = environment.check(operation);
96
+ var queryStatus = queryAvailability.status;
97
+ var hasFullQuery = queryStatus === 'available';
98
+ var canPartialRender = hasFullQuery || renderPolicy === 'partial' && queryStatus !== 'stale';
99
+ var shouldFetch;
100
+ var shouldRenderNow;
101
+
102
+ switch (fetchPolicy) {
103
+ case 'store-only':
104
+ {
105
+ shouldFetch = false;
106
+ shouldRenderNow = true;
107
+ break;
108
+ }
109
+
110
+ case 'store-or-network':
111
+ {
112
+ shouldFetch = !hasFullQuery;
113
+ shouldRenderNow = canPartialRender;
114
+ break;
115
+ }
116
+
117
+ case 'store-and-network':
118
+ {
119
+ shouldFetch = true;
120
+ shouldRenderNow = canPartialRender;
121
+ break;
122
+ }
123
+
124
+ case 'network-only':
125
+ default:
126
+ {
127
+ shouldFetch = true;
128
+ shouldRenderNow = false;
129
+ break;
130
+ }
131
+ }
132
+
133
+ var promise = shouldFetch ? executeOperationAndKeepUpToDate(environment, operation, updateCache) : undefined;
134
+
135
+ if (shouldRenderNow) {
136
+ return {
137
+ status: 'resolved',
138
+ result: constructQueryResult(operation)
139
+ };
140
+ } else {
141
+ !promise ? process.env.NODE_ENV !== "production" ? invariant(false, 'Should either fetch or render (or both), otherwise we would suspend forever.') : invariant(false) : void 0;
142
+ return {
143
+ status: 'pending',
144
+ promise: promise
145
+ };
146
+ }
147
+ }
148
+
149
+ function executeOperationAndKeepUpToDate(environment, operation, updateCache) {
150
+ var resolvePromise;
151
+ var promise = new Promise(function (r) {
152
+ resolvePromise = r;
153
+ }); // $FlowExpectedError[prop-missing] Expando to annotate Promises.
154
+
155
+ promise.displayName = 'Relay(' + operation.request.node.operation.name + ')';
156
+ var isFirstPayload = true; // FIXME We may still need to cancel network requests for live queries.
157
+
158
+ var fetchObservable = fetchQueryInternal(environment, operation);
159
+ fetchObservable.subscribe({
160
+ start: function start(subscription) {},
161
+ error: function error(_error) {
162
+ if (isFirstPayload) {
163
+ updateCache({
164
+ status: 'rejected',
165
+ error: _error
166
+ });
167
+ } else {
168
+ // TODO:T92030819 Remove this warning and actually throw the network error
169
+ // To complete this task we need to have a way of precisely tracking suspendable points
170
+ process.env.NODE_ENV !== "production" ? warning(false, 'getQueryResultOrFetchQuery: An incremental payload for query `%` returned an error: `%`:`%`.', operation.request.node.operation.name, _error.message, _error.stack) : void 0;
171
+ }
172
+
173
+ resolvePromise();
174
+ isFirstPayload = false;
175
+ },
176
+ next: function next(response) {
177
+ // Stop suspending on the first payload because of streaming, defer, etc.
178
+ updateCache({
179
+ status: 'resolved',
180
+ result: constructQueryResult(operation)
181
+ });
182
+ resolvePromise();
183
+ isFirstPayload = false;
184
+ },
185
+ complete: function complete() {
186
+ updateCache({
187
+ status: 'resolved',
188
+ result: constructQueryResult(operation)
189
+ });
190
+ resolvePromise();
191
+ isFirstPayload = false;
192
+ }
193
+ });
194
+ return promise;
195
+ }
196
+
197
+ module.exports = getQueryResultOrFetchQuery_REACT_CACHE;