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
@@ -0,0 +1,344 @@
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 _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
17
+
18
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
19
+
20
+ var SuspenseResource = require('../SuspenseResource');
21
+
22
+ var _require = require('./RelayReactCache'),
23
+ getCacheForType = _require.getCacheForType,
24
+ getCacheSignal = _require.getCacheSignal;
25
+
26
+ var invariant = require('invariant');
27
+
28
+ var _require2 = require('relay-runtime'),
29
+ RelayFeatureFlags = _require2.RelayFeatureFlags,
30
+ fetchQueryInternal = _require2.__internal.fetchQuery;
31
+
32
+ var warning = require("fbjs/lib/warning");
33
+
34
+ var DEFAULT_FETCH_POLICY = 'store-or-network';
35
+
36
+ var QueryCache = /*#__PURE__*/function () {
37
+ function QueryCache() {
38
+ this._map = new Map();
39
+ }
40
+
41
+ var _proto = QueryCache.prototype;
42
+
43
+ _proto.get = function get(environment, key) {
44
+ var forEnv = this._map.get(environment);
45
+
46
+ if (!forEnv) {
47
+ forEnv = new Map();
48
+
49
+ this._map.set(environment, forEnv);
50
+ }
51
+
52
+ return forEnv.get(key);
53
+ };
54
+
55
+ _proto.set = function set(environment, key, value) {
56
+ var forEnv = this._map.get(environment);
57
+
58
+ if (!forEnv) {
59
+ forEnv = new Map();
60
+
61
+ this._map.set(environment, forEnv);
62
+ }
63
+
64
+ forEnv.set(key, value);
65
+ };
66
+
67
+ _proto["delete"] = function _delete(environment, key) {
68
+ var forEnv = this._map.get(environment);
69
+
70
+ if (!forEnv) {
71
+ return;
72
+ }
73
+
74
+ forEnv["delete"](key);
75
+
76
+ if (forEnv.size === 0) {
77
+ this._map["delete"](environment);
78
+ }
79
+ };
80
+
81
+ return QueryCache;
82
+ }();
83
+
84
+ function createQueryCache() {
85
+ return new QueryCache();
86
+ }
87
+
88
+ var noopOnCommit = function noopOnCommit() {
89
+ return function () {
90
+ return undefined;
91
+ };
92
+ };
93
+
94
+ var noopPromise = new Promise(function () {});
95
+
96
+ function getQueryCacheKey(operation, fetchPolicy, renderPolicy, fetchKey) {
97
+ return "".concat(fetchPolicy, "-").concat(renderPolicy, "-").concat(operation.request.identifier, "-").concat(fetchKey !== null && fetchKey !== void 0 ? fetchKey : '');
98
+ }
99
+
100
+ function constructQueryResult(operation) {
101
+ var rootFragmentRef = {
102
+ __id: operation.fragment.dataID,
103
+ __fragments: (0, _defineProperty2["default"])({}, operation.fragment.node.name, operation.request.variables),
104
+ __fragmentOwner: operation.request
105
+ };
106
+ return {
107
+ fragmentNode: operation.request.node.fragment,
108
+ fragmentRef: rootFragmentRef
109
+ };
110
+ }
111
+
112
+ function makeInitialCacheEntry() {
113
+ return {
114
+ status: 'pending',
115
+ promise: noopPromise,
116
+ onCommit: noopOnCommit,
117
+ suspenseResource: null
118
+ };
119
+ }
120
+
121
+ function getQueryResultOrFetchQuery_REACT_CACHE(environment, queryOperationDescriptor, options) {
122
+ var _options$fetchPolicy, _options$renderPolicy;
123
+
124
+ var fetchPolicy = (_options$fetchPolicy = options === null || options === void 0 ? void 0 : options.fetchPolicy) !== null && _options$fetchPolicy !== void 0 ? _options$fetchPolicy : DEFAULT_FETCH_POLICY;
125
+ var renderPolicy = (_options$renderPolicy = options === null || options === void 0 ? void 0 : options.renderPolicy) !== null && _options$renderPolicy !== void 0 ? _options$renderPolicy : environment.UNSTABLE_getDefaultRenderPolicy();
126
+ var cache = getCacheForType(createQueryCache);
127
+ var cacheKey = getQueryCacheKey(queryOperationDescriptor, fetchPolicy, renderPolicy, options === null || options === void 0 ? void 0 : options.fetchKey);
128
+ var initialEntry = cache.get(environment, cacheKey);
129
+
130
+ function updateCache(updater) {
131
+ var currentEntry = cache.get(environment, cacheKey);
132
+
133
+ if (!currentEntry) {
134
+ currentEntry = makeInitialCacheEntry();
135
+ cache.set(environment, cacheKey, currentEntry);
136
+ } // $FlowExpectedError[prop-missing] Extra properties are passed in -- this is fine
137
+
138
+
139
+ var newStatus = updater(currentEntry); // $FlowExpectedError[cannot-spread-inexact] Flow cannot understand that this is valid...
140
+
141
+ cache.set(environment, cacheKey, (0, _objectSpread2["default"])((0, _objectSpread2["default"])({}, currentEntry), newStatus)); // ... but we can because QueryCacheEntry spreads QueryCacheEntryStatus, so spreading
142
+ // a QueryCacheEntryStatus into a QueryCacheEntry will result in a valid QueryCacheEntry.
143
+ } // Initiate a query to fetch the data if needed:
144
+
145
+
146
+ if (RelayFeatureFlags.USE_REACT_CACHE_LEGACY_TIMEOUTS) {
147
+ var _entry;
148
+
149
+ if (initialEntry === undefined) {
150
+ onCacheMiss(environment, queryOperationDescriptor, fetchPolicy, renderPolicy, updateCache, options === null || options === void 0 ? void 0 : options.fetchObservable);
151
+ var createdEntry = cache.get(environment, cacheKey);
152
+ !(createdEntry !== undefined) ? process.env.NODE_ENV !== "production" ? invariant(false, 'An entry should have been created by onCacheMiss. This is a bug in Relay.') : invariant(false) : void 0;
153
+ _entry = createdEntry;
154
+ } else {
155
+ _entry = initialEntry;
156
+ }
157
+
158
+ if (!_entry.suspenseResource) {
159
+ _entry.suspenseResource = new SuspenseResource(function () {
160
+ var retention = environment.retain(queryOperationDescriptor);
161
+ return {
162
+ dispose: function dispose() {
163
+ retention.dispose();
164
+ cache["delete"](environment, cacheKey);
165
+ }
166
+ };
167
+ });
168
+ }
169
+
170
+ if (_entry.onCommit === noopOnCommit) {
171
+ _entry.onCommit = function () {
172
+ !_entry.suspenseResource ? process.env.NODE_ENV !== "production" ? invariant(false, 'SuspenseResource should have been initialized. This is a bug in Relay.') : invariant(false) : void 0;
173
+
174
+ var retention = _entry.suspenseResource.permanentRetain(environment);
175
+
176
+ return function () {
177
+ retention.dispose();
178
+ };
179
+ };
180
+ }
181
+
182
+ _entry.suspenseResource.temporaryRetain(environment);
183
+ } else {
184
+ if (initialEntry === undefined) {
185
+ // This is the behavior we eventually want: We retain the query until the
186
+ // presiding Cache component unmounts, at which point the AbortSignal
187
+ // will be triggered.
188
+ onCacheMiss(environment, queryOperationDescriptor, fetchPolicy, renderPolicy, updateCache, options === null || options === void 0 ? void 0 : options.fetchObservable); // Since this is the first time rendering, retain the query. React will
189
+ // trigger the abort signal when this cache entry is no longer needed.
190
+
191
+ var retention = environment.retain(queryOperationDescriptor);
192
+
193
+ var dispose = function dispose() {
194
+ retention.dispose();
195
+ cache["delete"](environment, cacheKey);
196
+ };
197
+
198
+ var abortSignal = getCacheSignal();
199
+ abortSignal.addEventListener('abort', dispose, {
200
+ once: true
201
+ });
202
+ }
203
+ }
204
+
205
+ var entry = cache.get(environment, cacheKey); // could be a different entry now if synchronously resolved
206
+
207
+ !(entry !== undefined) ? process.env.NODE_ENV !== "production" ? invariant(false, 'An entry should have been created by onCacheMiss. This is a bug in Relay.') : invariant(false) : void 0;
208
+
209
+ switch (entry.status) {
210
+ case 'pending':
211
+ throw entry.promise;
212
+
213
+ case 'rejected':
214
+ throw entry.error;
215
+
216
+ case 'resolved':
217
+ return [entry.result, entry.onCommit];
218
+ }
219
+
220
+ !false ? process.env.NODE_ENV !== "production" ? invariant(false, 'switch statement should be exhaustive') : invariant(false) : void 0;
221
+ }
222
+
223
+ function onCacheMiss(environment, operation, fetchPolicy, renderPolicy, updateCache, customFetchObservable) {
224
+ // NB: Besides checking if the data is available, calling `check` will write missing
225
+ // data to the store using any missing data handlers specified in the environment.
226
+ var queryAvailability = environment.check(operation);
227
+ var queryStatus = queryAvailability.status;
228
+ var hasFullQuery = queryStatus === 'available';
229
+ var canPartialRender = hasFullQuery || renderPolicy === 'partial' && queryStatus !== 'stale';
230
+ var shouldFetch;
231
+ var shouldRenderNow;
232
+
233
+ switch (fetchPolicy) {
234
+ case 'store-only':
235
+ {
236
+ shouldFetch = false;
237
+ shouldRenderNow = true;
238
+ break;
239
+ }
240
+
241
+ case 'store-or-network':
242
+ {
243
+ shouldFetch = !hasFullQuery;
244
+ shouldRenderNow = canPartialRender;
245
+ break;
246
+ }
247
+
248
+ case 'store-and-network':
249
+ {
250
+ shouldFetch = true;
251
+ shouldRenderNow = canPartialRender;
252
+ break;
253
+ }
254
+
255
+ case 'network-only':
256
+ default:
257
+ {
258
+ shouldFetch = true;
259
+ shouldRenderNow = false;
260
+ break;
261
+ }
262
+ }
263
+
264
+ if (shouldFetch) {
265
+ executeOperationAndKeepUpToDate(environment, operation, updateCache, customFetchObservable);
266
+ updateCache(function (existing) {
267
+ switch (existing.status) {
268
+ case 'resolved':
269
+ return existing;
270
+
271
+ case 'rejected':
272
+ return existing;
273
+
274
+ case 'pending':
275
+ return shouldRenderNow ? {
276
+ status: 'resolved',
277
+ result: constructQueryResult(operation)
278
+ } : existing;
279
+ }
280
+ });
281
+ } else {
282
+ !shouldRenderNow ? process.env.NODE_ENV !== "production" ? invariant(false, 'Should either fetch or be willing to render. This is a bug in Relay.') : invariant(false) : void 0;
283
+ updateCache(function (_existing) {
284
+ return {
285
+ status: 'resolved',
286
+ result: constructQueryResult(operation)
287
+ };
288
+ });
289
+ }
290
+ }
291
+
292
+ function executeOperationAndKeepUpToDate(environment, operation, updateCache, customFetchObservable) {
293
+ var resolvePromise;
294
+ var promise = new Promise(function (r) {
295
+ resolvePromise = r;
296
+ }); // $FlowExpectedError[prop-missing] Expando to annotate Promises.
297
+
298
+ promise.displayName = 'Relay(' + operation.request.node.operation.name + ')';
299
+ var isFirstPayload = true; // FIXME We may still need to cancel network requests for live queries.
300
+
301
+ var fetchObservable = customFetchObservable !== null && customFetchObservable !== void 0 ? customFetchObservable : fetchQueryInternal(environment, operation);
302
+ fetchObservable.subscribe({
303
+ start: function start(subscription) {},
304
+ error: function error(_error) {
305
+ if (isFirstPayload) {
306
+ updateCache(function (_existing) {
307
+ return {
308
+ status: 'rejected',
309
+ error: _error
310
+ };
311
+ });
312
+ } else {
313
+ // TODO:T92030819 Remove this warning and actually throw the network error
314
+ // To complete this task we need to have a way of precisely tracking suspendable points
315
+ 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;
316
+ }
317
+
318
+ resolvePromise();
319
+ isFirstPayload = false;
320
+ },
321
+ next: function next(response) {
322
+ // Stop suspending on the first payload because of streaming, defer, etc.
323
+ updateCache(function (_existing) {
324
+ return {
325
+ status: 'resolved',
326
+ result: constructQueryResult(operation)
327
+ };
328
+ });
329
+ resolvePromise();
330
+ isFirstPayload = false;
331
+ }
332
+ }); // If the above subscription yields a value synchronously, then one of the updates
333
+ // above will have already happened and we'll now be in a resolved or rejected state.
334
+ // But in the usual case, we save the promise to the entry here:
335
+
336
+ updateCache(function (existing) {
337
+ return existing.status === 'pending' ? {
338
+ status: 'pending',
339
+ promise: promise
340
+ } : existing;
341
+ });
342
+ }
343
+
344
+ module.exports = getQueryResultOrFetchQuery_REACT_CACHE;