react-relay 13.2.0 → 14.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. package/ReactRelayContext.js +1 -1
  2. package/ReactRelayFragmentContainer.js.flow +7 -4
  3. package/ReactRelayPaginationContainer.js.flow +13 -8
  4. package/ReactRelayQueryFetcher.js.flow +1 -0
  5. package/ReactRelayQueryRenderer.js.flow +6 -2
  6. package/ReactRelayRefetchContainer.js.flow +10 -3
  7. package/__flowtests__/__generated__/ReactRelayFragmentContainerFlowtest_viewer.graphql.js.flow +2 -2
  8. package/__flowtests__/__generated__/ReactRelayFragmentContainerFlowtest_viewer2.graphql.js.flow +2 -2
  9. package/__flowtests__/__generated__/ReactRelayPaginationContainerFlowtestQuery.graphql.js.flow +3 -3
  10. package/__flowtests__/__generated__/ReactRelayPaginationContainerFlowtest_viewer.graphql.js.flow +3 -3
  11. package/__flowtests__/__generated__/ReactRelayRefetchContainerFlowtestQuery.graphql.js.flow +3 -3
  12. package/__flowtests__/__generated__/ReactRelayRefetchContainerFlowtest_viewer.graphql.js.flow +3 -3
  13. package/__flowtests__/__generated__/RelayModernFlowtest_badref.graphql.js.flow +2 -2
  14. package/__flowtests__/__generated__/RelayModernFlowtest_notref.graphql.js.flow +2 -2
  15. package/__flowtests__/__generated__/RelayModernFlowtest_user.graphql.js.flow +2 -2
  16. package/__flowtests__/__generated__/RelayModernFlowtest_users.graphql.js.flow +2 -2
  17. package/buildReactRelayContainer.js.flow +2 -2
  18. package/hooks.js +1 -1
  19. package/index.js +1 -1
  20. package/legacy.js +1 -1
  21. package/lib/ReactRelayQueryFetcher.js +1 -0
  22. package/lib/ReactRelayQueryRenderer.js +0 -1
  23. package/lib/readContext.js +2 -1
  24. package/lib/relay-hooks/FragmentResource.js +52 -10
  25. package/lib/relay-hooks/HooksImplementation.js +29 -0
  26. package/lib/relay-hooks/MatchContainer.js +1 -0
  27. package/lib/relay-hooks/QueryResource.js +2 -1
  28. package/lib/relay-hooks/react-cache/getQueryResultOrFetchQuery_REACT_CACHE.js +203 -56
  29. package/lib/relay-hooks/react-cache/useFragmentInternal_REACT_CACHE.js +254 -109
  30. package/lib/relay-hooks/react-cache/useFragment_REACT_CACHE.js +51 -0
  31. package/lib/relay-hooks/react-cache/useLazyLoadQuery_REACT_CACHE.js +13 -2
  32. package/lib/relay-hooks/react-cache/usePreloadedQuery_REACT_CACHE.js +125 -0
  33. package/lib/relay-hooks/useFragment.js +15 -1
  34. package/lib/relay-hooks/useLazyLoadQuery.js +18 -2
  35. package/lib/relay-hooks/useMutation.js +4 -5
  36. package/lib/relay-hooks/usePreloadedQuery.js +18 -2
  37. package/package.json +2 -2
  38. package/react-relay-hooks.js +2 -2
  39. package/react-relay-hooks.min.js +2 -2
  40. package/react-relay-legacy.js +2 -2
  41. package/react-relay-legacy.min.js +2 -2
  42. package/react-relay.js +2 -2
  43. package/react-relay.min.js +2 -2
  44. package/readContext.js.flow +1 -0
  45. package/relay-hooks/FragmentResource.js.flow +55 -9
  46. package/relay-hooks/HooksImplementation.js.flow +45 -0
  47. package/relay-hooks/MatchContainer.js.flow +8 -1
  48. package/relay-hooks/QueryResource.js.flow +4 -2
  49. package/relay-hooks/__flowtests__/__generated__/useFragmentFlowtest_user.graphql.js.flow +2 -2
  50. package/relay-hooks/__flowtests__/__generated__/useFragmentFlowtest_users.graphql.js.flow +2 -2
  51. package/relay-hooks/loadQuery.js.flow +2 -1
  52. package/relay-hooks/react-cache/getQueryResultOrFetchQuery_REACT_CACHE.js.flow +245 -64
  53. package/relay-hooks/react-cache/useFragmentInternal_REACT_CACHE.js.flow +242 -99
  54. package/relay-hooks/react-cache/useFragment_REACT_CACHE.js.flow +74 -0
  55. package/relay-hooks/react-cache/useLazyLoadQuery_REACT_CACHE.js.flow +10 -4
  56. package/relay-hooks/react-cache/usePreloadedQuery_REACT_CACHE.js.flow +153 -0
  57. package/relay-hooks/useFragment.js.flow +17 -10
  58. package/relay-hooks/useLazyLoadQuery.js.flow +38 -3
  59. package/relay-hooks/useMutation.js.flow +3 -3
  60. package/relay-hooks/usePreloadedQuery.js.flow +30 -2
  61. package/relay-hooks/useRefetchableFragmentNode.js.flow +26 -11
  62. package/relay-hooks/useSubscription.js.flow +14 -8
@@ -13,8 +13,12 @@
13
13
 
14
14
  var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
15
15
 
16
+ var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
17
+
16
18
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
17
19
 
20
+ var SuspenseResource = require('../SuspenseResource');
21
+
18
22
  var _require = require('./RelayReactCache'),
19
23
  getCacheForType = _require.getCacheForType,
20
24
  getCacheSignal = _require.getCacheSignal;
@@ -22,19 +26,75 @@ var _require = require('./RelayReactCache'),
22
26
  var invariant = require('invariant');
23
27
 
24
28
  var _require2 = require('relay-runtime'),
29
+ RelayFeatureFlags = _require2.RelayFeatureFlags,
25
30
  fetchQueryInternal = _require2.__internal.fetchQuery;
26
31
 
27
32
  var warning = require("fbjs/lib/warning");
28
33
 
29
34
  var DEFAULT_FETCH_POLICY = 'store-or-network';
30
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
+
31
84
  function createQueryCache() {
32
- return new Map();
85
+ return new QueryCache();
33
86
  }
34
87
 
35
- function getQueryCacheKey(operation, fetchPolicy, renderPolicy) {
36
- var cacheIdentifier = "".concat(fetchPolicy, "-").concat(renderPolicy, "-").concat(operation.request.identifier);
37
- return cacheIdentifier;
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 : '');
38
98
  }
39
99
 
40
100
  function constructQueryResult(operation) {
@@ -49,32 +109,103 @@ function constructQueryResult(operation) {
49
109
  };
50
110
  }
51
111
 
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();
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();
56
126
  var cache = getCacheForType(createQueryCache);
57
- var cacheKey = getQueryCacheKey(queryOperationDescriptor, fetchPolicy, renderPolicy);
58
- var entry = cache.get(cacheKey);
127
+ var cacheKey = getQueryCacheKey(queryOperationDescriptor, fetchPolicy, renderPolicy, options === null || options === void 0 ? void 0 : options.fetchKey);
128
+ var initialEntry = cache.get(environment, cacheKey);
59
129
 
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
- });
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
+ }
76
203
  }
77
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
+
78
209
  switch (entry.status) {
79
210
  case 'pending':
80
211
  throw entry.promise;
@@ -83,13 +214,13 @@ function getQueryResultOrFetchQuery_REACT_CACHE(environment, queryOperationDescr
83
214
  throw entry.error;
84
215
 
85
216
  case 'resolved':
86
- return entry.result;
217
+ return [entry.result, entry.onCommit];
87
218
  }
88
219
 
89
220
  !false ? process.env.NODE_ENV !== "production" ? invariant(false, 'switch statement should be exhaustive') : invariant(false) : void 0;
90
221
  }
91
222
 
92
- function onCacheMiss(environment, operation, fetchPolicy, renderPolicy, updateCache) {
223
+ function onCacheMiss(environment, operation, fetchPolicy, renderPolicy, updateCache, customFetchObservable) {
93
224
  // NB: Besides checking if the data is available, calling `check` will write missing
94
225
  // data to the store using any missing data handlers specified in the environment.
95
226
  var queryAvailability = environment.check(operation);
@@ -130,23 +261,35 @@ function onCacheMiss(environment, operation, fetchPolicy, renderPolicy, updateCa
130
261
  }
131
262
  }
132
263
 
133
- var promise = shouldFetch ? executeOperationAndKeepUpToDate(environment, operation, updateCache) : undefined;
264
+ if (shouldFetch) {
265
+ executeOperationAndKeepUpToDate(environment, operation, updateCache, customFetchObservable);
266
+ updateCache(function (existing) {
267
+ switch (existing.status) {
268
+ case 'resolved':
269
+ return existing;
134
270
 
135
- if (shouldRenderNow) {
136
- return {
137
- status: 'resolved',
138
- result: constructQueryResult(operation)
139
- };
271
+ case 'rejected':
272
+ return existing;
273
+
274
+ case 'pending':
275
+ return shouldRenderNow ? {
276
+ status: 'resolved',
277
+ result: constructQueryResult(operation)
278
+ } : existing;
279
+ }
280
+ });
140
281
  } 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
- };
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
+ });
146
289
  }
147
290
  }
148
291
 
149
- function executeOperationAndKeepUpToDate(environment, operation, updateCache) {
292
+ function executeOperationAndKeepUpToDate(environment, operation, updateCache, customFetchObservable) {
150
293
  var resolvePromise;
151
294
  var promise = new Promise(function (r) {
152
295
  resolvePromise = r;
@@ -155,14 +298,16 @@ function executeOperationAndKeepUpToDate(environment, operation, updateCache) {
155
298
  promise.displayName = 'Relay(' + operation.request.node.operation.name + ')';
156
299
  var isFirstPayload = true; // FIXME We may still need to cancel network requests for live queries.
157
300
 
158
- var fetchObservable = fetchQueryInternal(environment, operation);
301
+ var fetchObservable = customFetchObservable !== null && customFetchObservable !== void 0 ? customFetchObservable : fetchQueryInternal(environment, operation);
159
302
  fetchObservable.subscribe({
160
303
  start: function start(subscription) {},
161
304
  error: function error(_error) {
162
305
  if (isFirstPayload) {
163
- updateCache({
164
- status: 'rejected',
165
- error: _error
306
+ updateCache(function (_existing) {
307
+ return {
308
+ status: 'rejected',
309
+ error: _error
310
+ };
166
311
  });
167
312
  } else {
168
313
  // TODO:T92030819 Remove this warning and actually throw the network error
@@ -175,23 +320,25 @@ function executeOperationAndKeepUpToDate(environment, operation, updateCache) {
175
320
  },
176
321
  next: function next(response) {
177
322
  // 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)
323
+ updateCache(function (_existing) {
324
+ return {
325
+ status: 'resolved',
326
+ result: constructQueryResult(operation)
327
+ };
189
328
  });
190
329
  resolvePromise();
191
330
  isFirstPayload = false;
192
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;
193
341
  });
194
- return promise;
195
342
  }
196
343
 
197
344
  module.exports = getQueryResultOrFetchQuery_REACT_CACHE;