@khanacademy/wonder-blocks-data 2.3.4 → 3.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.
- package/CHANGELOG.md +7 -0
- package/dist/es/index.js +212 -446
- package/dist/index.js +230 -478
- package/docs.md +19 -13
- package/package.json +2 -3
- package/src/__tests__/__snapshots__/generated-snapshot.test.js.snap +40 -160
- package/src/__tests__/generated-snapshot.test.js +15 -195
- package/src/components/__tests__/data.test.js +159 -965
- package/src/components/__tests__/intercept-data.test.js +9 -66
- package/src/components/__tests__/track-data.test.js +6 -5
- package/src/components/data.js +9 -117
- package/src/components/data.md +38 -60
- package/src/components/intercept-data.js +2 -34
- package/src/components/intercept-data.md +7 -105
- package/src/hooks/__tests__/use-data.test.js +790 -0
- package/src/hooks/use-data.js +138 -0
- package/src/index.js +1 -3
- package/src/util/__tests__/memory-cache.test.js +134 -35
- package/src/util/__tests__/request-fulfillment.test.js +21 -36
- package/src/util/__tests__/request-handler.test.js +30 -30
- package/src/util/__tests__/request-tracking.test.js +29 -30
- package/src/util/__tests__/response-cache.test.js +521 -561
- package/src/util/__tests__/result-from-cache-entry.test.js +68 -0
- package/src/util/memory-cache.js +18 -14
- package/src/util/request-fulfillment.js +4 -0
- package/src/util/request-handler.js +2 -27
- package/src/util/request-handler.md +0 -32
- package/src/util/response-cache.js +50 -110
- package/src/util/result-from-cache-entry.js +38 -0
- package/src/util/types.js +14 -35
- package/LICENSE +0 -21
- package/src/components/__tests__/intercept-cache.test.js +0 -124
- package/src/components/__tests__/internal-data.test.js +0 -1030
- package/src/components/intercept-cache.js +0 -79
- package/src/components/intercept-cache.md +0 -103
- package/src/components/internal-data.js +0 -219
- package/src/util/__tests__/no-cache.test.js +0 -112
- package/src/util/no-cache.js +0 -67
- package/src/util/no-cache.md +0 -66
package/dist/index.js
CHANGED
|
@@ -82,7 +82,7 @@ module.exports =
|
|
|
82
82
|
/******/
|
|
83
83
|
/******/
|
|
84
84
|
/******/ // Load entry module and return exports
|
|
85
|
-
/******/ return __webpack_require__(__webpack_require__.s =
|
|
85
|
+
/******/ return __webpack_require__(__webpack_require__.s = 13);
|
|
86
86
|
/******/ })
|
|
87
87
|
/************************************************************************/
|
|
88
88
|
/******/ ([
|
|
@@ -93,15 +93,19 @@ module.exports = require("react");
|
|
|
93
93
|
|
|
94
94
|
/***/ }),
|
|
95
95
|
/* 1 */
|
|
96
|
+
/***/ (function(module, exports) {
|
|
97
|
+
|
|
98
|
+
module.exports = require("@khanacademy/wonder-blocks-core");
|
|
99
|
+
|
|
100
|
+
/***/ }),
|
|
101
|
+
/* 2 */
|
|
96
102
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
97
103
|
|
|
98
104
|
"use strict";
|
|
99
105
|
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return ResponseCache; });
|
|
100
|
-
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(
|
|
106
|
+
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
|
|
101
107
|
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__);
|
|
102
108
|
/* harmony import */ var _memory_cache_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(7);
|
|
103
|
-
/* harmony import */ var _no_cache_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(5);
|
|
104
|
-
|
|
105
109
|
|
|
106
110
|
|
|
107
111
|
|
|
@@ -126,24 +130,22 @@ class ResponseCache {
|
|
|
126
130
|
return _default;
|
|
127
131
|
}
|
|
128
132
|
|
|
129
|
-
constructor(
|
|
133
|
+
constructor(hydrationCache = null, ssrOnlyCache = null) {
|
|
130
134
|
this.initialize = source => {
|
|
131
|
-
if (this.
|
|
135
|
+
if (this._hydrationCache.inUse) {
|
|
132
136
|
throw new Error("Cannot initialize data response cache more than once");
|
|
133
137
|
}
|
|
134
138
|
|
|
135
139
|
try {
|
|
136
|
-
this.
|
|
140
|
+
this._hydrationCache = new _memory_cache_js__WEBPACK_IMPORTED_MODULE_1__[/* default */ "a"](source);
|
|
137
141
|
} catch (e) {
|
|
138
142
|
throw new Error(`An error occurred trying to initialize the data response cache: ${e}`);
|
|
139
143
|
}
|
|
140
144
|
};
|
|
141
145
|
|
|
142
|
-
this.cacheData = (handler, options, data) => {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
});
|
|
146
|
-
};
|
|
146
|
+
this.cacheData = (handler, options, data) => this._setCacheEntry(handler, options, {
|
|
147
|
+
data
|
|
148
|
+
});
|
|
147
149
|
|
|
148
150
|
this.cacheError = (handler, options, error) => {
|
|
149
151
|
const errorMessage = typeof error === "string" ? error : error.message;
|
|
@@ -153,110 +155,64 @@ class ResponseCache {
|
|
|
153
155
|
};
|
|
154
156
|
|
|
155
157
|
this.getEntry = (handler, options) => {
|
|
156
|
-
//
|
|
157
|
-
//
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
// This allows us to use our hydrated cache during hydration.
|
|
167
|
-
// If we just returned null when the custom cache didn't have it,
|
|
168
|
-
// we would never hydrate properly.
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
const internalEntry = this._defaultCache(handler).retrieve(handler, options); // If we are not server-side and we hydrated something that the custom
|
|
172
|
-
// cache didn't have, we need to make sure the custom cache contains
|
|
173
|
-
// that value.
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
if (this._ssrOnlyCache == null && handler.cache != null && internalEntry != null) {
|
|
177
|
-
// Yes, if this throws, we will have a problem. We want that.
|
|
178
|
-
// Bad cache implementations should be overt.
|
|
179
|
-
handler.cache.store(handler, options, internalEntry); // We now delete this from our in-memory cache as we don't need it.
|
|
158
|
+
// Get the cached entry for this value.
|
|
159
|
+
// If the handler wants WB Data to hydrate (i.e. handler.hydrate is
|
|
160
|
+
// true), we use our hydration cache. Otherwise, if we're server-side
|
|
161
|
+
// we use our SSR-only cache. Otherwise, there's no entry to return.
|
|
162
|
+
const cache = handler.hydrate ? this._hydrationCache : _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__["Server"].isServerSide() ? this._ssrOnlyCache : undefined;
|
|
163
|
+
const internalEntry = cache == null ? void 0 : cache.retrieve(handler, options); // If we are not server-side and we hydrated something, let's clear
|
|
164
|
+
// that from the hydration cache to save memory.
|
|
165
|
+
|
|
166
|
+
if (this._ssrOnlyCache == null && internalEntry != null) {
|
|
167
|
+
// We now delete this from our hydration cache as we don't need it.
|
|
180
168
|
// This does mean that if another handler of the same type but
|
|
181
|
-
// without
|
|
182
|
-
//
|
|
183
|
-
//
|
|
184
|
-
|
|
185
|
-
this.
|
|
169
|
+
// without some sort of linked cache won't get the value, but
|
|
170
|
+
// that's not an expected use-case. If two different places use the
|
|
171
|
+
// same handler and options (i.e. the same request), then the
|
|
172
|
+
// handler should cater to that to ensure they share the result.
|
|
173
|
+
this._hydrationCache.remove(handler, options);
|
|
186
174
|
}
|
|
187
175
|
|
|
188
176
|
return internalEntry;
|
|
189
177
|
};
|
|
190
178
|
|
|
191
179
|
this.remove = (handler, options) => {
|
|
180
|
+
var _this$_ssrOnlyCache$r, _this$_ssrOnlyCache;
|
|
181
|
+
|
|
192
182
|
// NOTE(somewhatabstract): We could invoke removeAll with a predicate
|
|
193
183
|
// to match the key of the entry we're removing, but that's an
|
|
194
184
|
// inefficient way to remove a single item, so let's not do that.
|
|
195
|
-
//
|
|
196
|
-
|
|
197
|
-
const customCache = this._ssrOnlyCache == null ? handler.cache : null;
|
|
198
|
-
const removedCustom = !!(customCache != null && customCache.remove(handler, options)); // Delete the entry from our internal cache.
|
|
199
|
-
// Even if we have a custom cache, we want to make sure we still
|
|
200
|
-
// removed the same value from internal cache since this could be
|
|
201
|
-
// getting called before hydration for some complex advanced usage
|
|
202
|
-
// reason.
|
|
203
|
-
|
|
204
|
-
return this._defaultCache(handler).remove(handler, options) || removedCustom;
|
|
185
|
+
// Delete the entry from the appropriate cache.
|
|
186
|
+
return handler.hydrate ? this._hydrationCache.remove(handler, options) : (_this$_ssrOnlyCache$r = (_this$_ssrOnlyCache = this._ssrOnlyCache) == null ? void 0 : _this$_ssrOnlyCache.remove(handler, options)) != null ? _this$_ssrOnlyCache$r : false;
|
|
205
187
|
};
|
|
206
188
|
|
|
207
189
|
this.removeAll = (handler, predicate) => {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
// Even if we have a custom cache, we want to make sure we still
|
|
213
|
-
// removed the same value from internal cache since this could be
|
|
214
|
-
// getting called before hydration for some complex advanced usage
|
|
215
|
-
// reason.
|
|
216
|
-
|
|
217
|
-
const removedCount = this._defaultCache(handler).removeAll(handler, predicate); // We have no idea which keys were removed from which caches,
|
|
218
|
-
// so we can't dedupe the remove counts based on keys.
|
|
219
|
-
// That's why we return the total records deleted rather than the
|
|
220
|
-
// total keys deleted.
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
return removedCount + removedCountCustom;
|
|
190
|
+
var _this$_ssrOnlyCache$r2, _this$_ssrOnlyCache2;
|
|
191
|
+
|
|
192
|
+
// Apply the predicate to what we have in the appropriate cache.
|
|
193
|
+
return handler.hydrate ? this._hydrationCache.removeAll(handler, predicate) : (_this$_ssrOnlyCache$r2 = (_this$_ssrOnlyCache2 = this._ssrOnlyCache) == null ? void 0 : _this$_ssrOnlyCache2.removeAll(handler, predicate)) != null ? _this$_ssrOnlyCache$r2 : 0;
|
|
224
194
|
};
|
|
225
195
|
|
|
226
196
|
this.cloneHydratableData = () => {
|
|
227
197
|
// We return our hydration cache only.
|
|
228
|
-
return this.
|
|
198
|
+
return this._hydrationCache.cloneData();
|
|
229
199
|
};
|
|
230
200
|
|
|
231
201
|
this._ssrOnlyCache = _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__["Server"].isServerSide() ? ssrOnlyCache || new _memory_cache_js__WEBPACK_IMPORTED_MODULE_1__[/* default */ "a"]() : undefined;
|
|
232
|
-
this.
|
|
233
|
-
}
|
|
234
|
-
/**
|
|
235
|
-
* Returns the default cache to use for the given handler.
|
|
236
|
-
*/
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
_defaultCache(handler) {
|
|
240
|
-
if (handler.hydrate) {
|
|
241
|
-
return this._hydrationAndDefaultCache;
|
|
242
|
-
} // If the handler doesn't want to hydrate, we return the SSR-only cache.
|
|
243
|
-
// If we are client-side, we return our non-caching implementation.
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
return this._ssrOnlyCache || _no_cache_js__WEBPACK_IMPORTED_MODULE_2__[/* default */ "a"].Default;
|
|
202
|
+
this._hydrationCache = hydrationCache || new _memory_cache_js__WEBPACK_IMPORTED_MODULE_1__[/* default */ "a"]();
|
|
247
203
|
}
|
|
248
204
|
|
|
249
205
|
_setCacheEntry(handler, options, entry) {
|
|
250
206
|
const frozenEntry = Object.freeze(entry);
|
|
251
207
|
|
|
252
|
-
if (this._ssrOnlyCache
|
|
253
|
-
// We are
|
|
254
|
-
//
|
|
255
|
-
handler.
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
208
|
+
if (this._ssrOnlyCache != null) {
|
|
209
|
+
// We are server-side.
|
|
210
|
+
// We need to store this value.
|
|
211
|
+
if (handler.hydrate) {
|
|
212
|
+
this._hydrationCache.store(handler, options, frozenEntry);
|
|
213
|
+
} else {
|
|
214
|
+
this._ssrOnlyCache.store(handler, options, frozenEntry);
|
|
215
|
+
}
|
|
260
216
|
}
|
|
261
217
|
|
|
262
218
|
return frozenEntry;
|
|
@@ -270,12 +226,6 @@ class ResponseCache {
|
|
|
270
226
|
|
|
271
227
|
}
|
|
272
228
|
|
|
273
|
-
/***/ }),
|
|
274
|
-
/* 2 */
|
|
275
|
-
/***/ (function(module, exports) {
|
|
276
|
-
|
|
277
|
-
module.exports = require("@khanacademy/wonder-blocks-core");
|
|
278
|
-
|
|
279
229
|
/***/ }),
|
|
280
230
|
/* 3 */
|
|
281
231
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
@@ -285,7 +235,7 @@ module.exports = require("@khanacademy/wonder-blocks-core");
|
|
|
285
235
|
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return RequestTracker; });
|
|
286
236
|
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0);
|
|
287
237
|
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
|
|
288
|
-
/* harmony import */ var _response_cache_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(
|
|
238
|
+
/* harmony import */ var _response_cache_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2);
|
|
289
239
|
/* harmony import */ var _request_fulfillment_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6);
|
|
290
240
|
|
|
291
241
|
|
|
@@ -450,42 +400,133 @@ const InterceptContext = /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["create
|
|
|
450
400
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
451
401
|
|
|
452
402
|
"use strict";
|
|
453
|
-
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
* handler as this ensures that cache space and memory are never used for the
|
|
464
|
-
* requested data after hydration has finished.
|
|
465
|
-
*/
|
|
403
|
+
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return useData; });
|
|
404
|
+
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
|
|
405
|
+
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__);
|
|
406
|
+
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(0);
|
|
407
|
+
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
|
|
408
|
+
/* harmony import */ var _util_request_fulfillment_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6);
|
|
409
|
+
/* harmony import */ var _components_intercept_context_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(4);
|
|
410
|
+
/* harmony import */ var _util_request_tracking_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(3);
|
|
411
|
+
/* harmony import */ var _util_result_from_cache_entry_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(12);
|
|
412
|
+
/* harmony import */ var _util_response_cache_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(2);
|
|
466
413
|
|
|
467
|
-
class NoCache {
|
|
468
|
-
constructor() {
|
|
469
|
-
this.store = (handler, options, entry) => {
|
|
470
|
-
/* empty */
|
|
471
|
-
};
|
|
472
414
|
|
|
473
|
-
this.retrieve = (handler, options) => null;
|
|
474
415
|
|
|
475
|
-
this.remove = (handler, options) => false;
|
|
476
416
|
|
|
477
|
-
this.removeAll = (handler, predicate) => 0;
|
|
478
|
-
}
|
|
479
417
|
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
const useData = (handler, options) => {
|
|
421
|
+
// If we're server-side or hydrating, we'll have a cached entry to use.
|
|
422
|
+
// So we get that and use it to initialize our state.
|
|
423
|
+
// This works in both hydration and SSR because the very first call to
|
|
424
|
+
// this will have cached data in those cases as it will be present on the
|
|
425
|
+
// initial render - and subsequent renders on the client it will be null.
|
|
426
|
+
const cachedResult = _util_response_cache_js__WEBPACK_IMPORTED_MODULE_6__[/* ResponseCache */ "a"].Default.getEntry(handler, options);
|
|
427
|
+
const [result, setResult] = Object(react__WEBPACK_IMPORTED_MODULE_1__["useState"])(cachedResult); // We only track data requests when we are server-side and we don't
|
|
428
|
+
// already have a result, as given by the cachedData (which is also the
|
|
429
|
+
// initial value for the result state).
|
|
430
|
+
|
|
431
|
+
const maybeTrack = Object(react__WEBPACK_IMPORTED_MODULE_1__["useContext"])(_util_request_tracking_js__WEBPACK_IMPORTED_MODULE_4__[/* TrackerContext */ "b"]);
|
|
432
|
+
|
|
433
|
+
if (result == null && _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__["Server"].isServerSide()) {
|
|
434
|
+
maybeTrack == null ? void 0 : maybeTrack(handler, options);
|
|
435
|
+
} // Lookup to see if there's an interceptor for the handler.
|
|
436
|
+
// If we have one, we need to replace the handler with one that
|
|
437
|
+
// uses the interceptor.
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
const interceptorMap = Object(react__WEBPACK_IMPORTED_MODULE_1__["useContext"])(_components_intercept_context_js__WEBPACK_IMPORTED_MODULE_3__[/* default */ "a"]);
|
|
441
|
+
const interceptor = interceptorMap[handler.type]; // We need to update our request when the handler changes or the key
|
|
442
|
+
// to the options change, so we keep track of those.
|
|
443
|
+
// However, even if we are hydrating from cache, we still need to make the
|
|
444
|
+
// request at least once, so we do not initialize these references.
|
|
445
|
+
|
|
446
|
+
const handlerRef = Object(react__WEBPACK_IMPORTED_MODULE_1__["useRef"])();
|
|
447
|
+
const keyRef = Object(react__WEBPACK_IMPORTED_MODULE_1__["useRef"])();
|
|
448
|
+
const interceptorRef = Object(react__WEBPACK_IMPORTED_MODULE_1__["useRef"])(); // This effect will ensure that we fulfill the request as desired.
|
|
449
|
+
|
|
450
|
+
Object(react__WEBPACK_IMPORTED_MODULE_1__["useEffect"])(() => {
|
|
451
|
+
// If we are server-side, then just skip the effect. We track requests
|
|
452
|
+
// during SSR and fulfill them outside of the React render cycle.
|
|
453
|
+
// NOTE: This shouldn't happen since effects would not run on the server
|
|
454
|
+
// but let's be defensive - I think it makes the code clearer.
|
|
455
|
+
|
|
456
|
+
/* istanbul ignore next */
|
|
457
|
+
if (_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__["Server"].isServerSide()) {
|
|
458
|
+
return;
|
|
459
|
+
} // Update our refs to the current handler and key.
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
handlerRef.current = handler;
|
|
463
|
+
keyRef.current = handler.getKey(options);
|
|
464
|
+
interceptorRef.current = interceptor; // If we're not hydrating a result, we want to make sure we set our
|
|
465
|
+
// result to null so that we're in the loading state.
|
|
466
|
+
|
|
467
|
+
if (cachedResult == null) {
|
|
468
|
+
// Mark ourselves as loading.
|
|
469
|
+
setResult(null);
|
|
483
470
|
}
|
|
484
471
|
|
|
485
|
-
|
|
486
|
-
|
|
472
|
+
const getMaybeInterceptedHandler = () => {
|
|
473
|
+
if (interceptor == null) {
|
|
474
|
+
return handler;
|
|
475
|
+
}
|
|
487
476
|
|
|
488
|
-
|
|
477
|
+
const fulfillRequestFn = options => {
|
|
478
|
+
var _interceptor$fulfillR;
|
|
479
|
+
|
|
480
|
+
return (_interceptor$fulfillR = interceptor.fulfillRequest(options)) != null ? _interceptor$fulfillR : handler.fulfillRequest(options);
|
|
481
|
+
};
|
|
482
|
+
|
|
483
|
+
return {
|
|
484
|
+
fulfillRequest: fulfillRequestFn,
|
|
485
|
+
getKey: options => handler.getKey(options),
|
|
486
|
+
type: handler.type,
|
|
487
|
+
hydrate: handler.hydrate
|
|
488
|
+
};
|
|
489
|
+
}; // We aren't server-side, so let's make the request.
|
|
490
|
+
// The request handler is in control of whether that request actually
|
|
491
|
+
// happens or not.
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
let cancel = false;
|
|
495
|
+
_util_request_fulfillment_js__WEBPACK_IMPORTED_MODULE_2__[/* RequestFulfillment */ "a"].Default.fulfill(getMaybeInterceptedHandler(), options).then(updateEntry => {
|
|
496
|
+
if (cancel) {
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
setResult(updateEntry);
|
|
501
|
+
return;
|
|
502
|
+
}).catch(e => {
|
|
503
|
+
if (cancel) {
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* We should never get here as errors in fulfillment are part
|
|
508
|
+
* of the `then`, but if we do.
|
|
509
|
+
*/
|
|
510
|
+
// eslint-disable-next-line no-console
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
console.error(`Unexpected error occurred during data fulfillment: ${e}`);
|
|
514
|
+
setResult({
|
|
515
|
+
data: null,
|
|
516
|
+
error: typeof e === "string" ? e : e.message
|
|
517
|
+
});
|
|
518
|
+
return;
|
|
519
|
+
});
|
|
520
|
+
return () => {
|
|
521
|
+
cancel = true;
|
|
522
|
+
}; // - handler.getKey is a proxy for options
|
|
523
|
+
// - We don't want to trigger on cachedResult changing, we're
|
|
524
|
+
// just using that as a flag for render state if the other things
|
|
525
|
+
// trigger this effect.
|
|
526
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
527
|
+
}, [handler, handler.getKey(options), interceptor]);
|
|
528
|
+
return Object(_util_result_from_cache_entry_js__WEBPACK_IMPORTED_MODULE_5__[/* resultFromCacheEntry */ "a"])(result);
|
|
529
|
+
};
|
|
489
530
|
|
|
490
531
|
/***/ }),
|
|
491
532
|
/* 6 */
|
|
@@ -493,7 +534,7 @@ class NoCache {
|
|
|
493
534
|
|
|
494
535
|
"use strict";
|
|
495
536
|
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return RequestFulfillment; });
|
|
496
|
-
/* harmony import */ var _response_cache_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(
|
|
537
|
+
/* harmony import */ var _response_cache_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
|
|
497
538
|
|
|
498
539
|
|
|
499
540
|
let _default;
|
|
@@ -546,6 +587,8 @@ class RequestFulfillment {
|
|
|
546
587
|
delete handlerRequests[key];
|
|
547
588
|
/**
|
|
548
589
|
* Let's cache the data!
|
|
590
|
+
*
|
|
591
|
+
* NOTE: This only caches when we're server side.
|
|
549
592
|
*/
|
|
550
593
|
|
|
551
594
|
return cacheData(handler, options, data);
|
|
@@ -553,6 +596,8 @@ class RequestFulfillment {
|
|
|
553
596
|
delete handlerRequests[key];
|
|
554
597
|
/**
|
|
555
598
|
* Let's cache the error!
|
|
599
|
+
*
|
|
600
|
+
* NOTE: This only caches when we're server side.
|
|
556
601
|
*/
|
|
557
602
|
|
|
558
603
|
return cacheError(handler, options, error);
|
|
@@ -596,9 +641,7 @@ function deepClone(source) {
|
|
|
596
641
|
*
|
|
597
642
|
* Special case cache implementation for the memory cache.
|
|
598
643
|
*
|
|
599
|
-
* This is only used within our framework
|
|
600
|
-
* provide this as a custom cache as the framework will default to this in the
|
|
601
|
-
* absence of a custom cache. We use this for SSR too (see ./response-cache.js).
|
|
644
|
+
* This is only used within our framework for SSR (see ./response-cache.js).
|
|
602
645
|
*/
|
|
603
646
|
|
|
604
647
|
|
|
@@ -606,7 +649,7 @@ class MemoryCache {
|
|
|
606
649
|
constructor(source = null) {
|
|
607
650
|
this.store = (handler, options, entry) => {
|
|
608
651
|
const requestType = handler.type;
|
|
609
|
-
const frozenEntry = Object.
|
|
652
|
+
const frozenEntry = Object.freeze(entry); // Ensure we have a cache location for this handler type.
|
|
610
653
|
|
|
611
654
|
this._cache[requestType] = this._cache[requestType] || {}; // Cache the data.
|
|
612
655
|
|
|
@@ -666,16 +709,22 @@ class MemoryCache {
|
|
|
666
709
|
|
|
667
710
|
if (!handlerCache) {
|
|
668
711
|
return 0;
|
|
669
|
-
}
|
|
670
|
-
|
|
712
|
+
}
|
|
671
713
|
|
|
672
714
|
let removedCount = 0;
|
|
673
715
|
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
716
|
+
if (typeof predicate === "function") {
|
|
717
|
+
// Apply the predicate to what we have cached.
|
|
718
|
+
for (const [key, entry] of Object.entries(handlerCache)) {
|
|
719
|
+
if (predicate(key, entry)) {
|
|
720
|
+
removedCount++;
|
|
721
|
+
delete handlerCache[key];
|
|
722
|
+
}
|
|
678
723
|
}
|
|
724
|
+
} else {
|
|
725
|
+
// We're removing everything so delete the entire subcache.
|
|
726
|
+
removedCount = Object.keys(handlerCache).length;
|
|
727
|
+
delete this._cache[requestType];
|
|
679
728
|
}
|
|
680
729
|
|
|
681
730
|
return removedCount;
|
|
@@ -705,6 +754,12 @@ class MemoryCache {
|
|
|
705
754
|
}
|
|
706
755
|
}
|
|
707
756
|
}
|
|
757
|
+
/**
|
|
758
|
+
* Indicate if this cache is being used or now.
|
|
759
|
+
*
|
|
760
|
+
* When the cache has entries, returns `true`; otherwise, returns `false`.
|
|
761
|
+
*/
|
|
762
|
+
|
|
708
763
|
|
|
709
764
|
get inUse() {
|
|
710
765
|
return Object.keys(this._cache).length > 0;
|
|
@@ -725,9 +780,8 @@ class MemoryCache {
|
|
|
725
780
|
* use with the Wonder Blocks Data framework.
|
|
726
781
|
*/
|
|
727
782
|
class RequestHandler {
|
|
728
|
-
constructor(type,
|
|
783
|
+
constructor(type, hydrate = true) {
|
|
729
784
|
this._type = type;
|
|
730
|
-
this._cache = cache || null;
|
|
731
785
|
this._hydrate = !!hydrate;
|
|
732
786
|
}
|
|
733
787
|
|
|
@@ -735,26 +789,10 @@ class RequestHandler {
|
|
|
735
789
|
return this._type;
|
|
736
790
|
}
|
|
737
791
|
|
|
738
|
-
get cache() {
|
|
739
|
-
return this._cache;
|
|
740
|
-
}
|
|
741
|
-
|
|
742
792
|
get hydrate() {
|
|
743
793
|
return this._hydrate;
|
|
744
794
|
}
|
|
745
795
|
|
|
746
|
-
shouldRefreshCache(options, cachedEntry) {
|
|
747
|
-
/**
|
|
748
|
-
* By default, the cache needs a refresh if the current entry is an
|
|
749
|
-
* error.
|
|
750
|
-
*
|
|
751
|
-
* This means that an error will cause a re-request on render.
|
|
752
|
-
* Useful if the server rendered an error, as it means the client
|
|
753
|
-
* will update after rehydration.
|
|
754
|
-
*/
|
|
755
|
-
return cachedEntry == null || cachedEntry.error != null;
|
|
756
|
-
}
|
|
757
|
-
|
|
758
796
|
getKey(options) {
|
|
759
797
|
try {
|
|
760
798
|
return options === undefined ? "undefined" : JSON.stringify(options);
|
|
@@ -777,7 +815,7 @@ class RequestHandler {
|
|
|
777
815
|
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return TrackData; });
|
|
778
816
|
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0);
|
|
779
817
|
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
|
|
780
|
-
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(
|
|
818
|
+
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(1);
|
|
781
819
|
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_1__);
|
|
782
820
|
/* harmony import */ var _util_request_tracking_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(3);
|
|
783
821
|
|
|
@@ -805,14 +843,9 @@ class TrackData extends react__WEBPACK_IMPORTED_MODULE_0__["Component"] {
|
|
|
805
843
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
806
844
|
|
|
807
845
|
"use strict";
|
|
808
|
-
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Data; });
|
|
809
846
|
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0);
|
|
810
847
|
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
|
|
811
|
-
/* harmony import */ var
|
|
812
|
-
/* harmony import */ var _internal_data_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(13);
|
|
813
|
-
/* harmony import */ var _intercept_context_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(4);
|
|
814
|
-
|
|
815
|
-
|
|
848
|
+
/* harmony import */ var _hooks_use_data_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5);
|
|
816
849
|
|
|
817
850
|
|
|
818
851
|
|
|
@@ -821,83 +854,12 @@ class TrackData extends react__WEBPACK_IMPORTED_MODULE_0__["Component"] {
|
|
|
821
854
|
* requirements can be placed in a React application in a manner that will
|
|
822
855
|
* support server-side rendering and efficient caching.
|
|
823
856
|
*/
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
} = this.props;
|
|
829
|
-
|
|
830
|
-
if (!interceptor) {
|
|
831
|
-
return handler;
|
|
832
|
-
}
|
|
833
|
-
|
|
834
|
-
const {
|
|
835
|
-
fulfillRequest,
|
|
836
|
-
shouldRefreshCache
|
|
837
|
-
} = interceptor;
|
|
838
|
-
const fulfillRequestFn = fulfillRequest ? options => {
|
|
839
|
-
const interceptedResult = fulfillRequest(options);
|
|
840
|
-
return interceptedResult != null ? interceptedResult : handler.fulfillRequest(options);
|
|
841
|
-
} : options => handler.fulfillRequest(options);
|
|
842
|
-
const shouldRefreshCacheFn = shouldRefreshCache ? (options, cacheEntry) => {
|
|
843
|
-
const interceptedResult = shouldRefreshCache(options, cacheEntry);
|
|
844
|
-
return interceptedResult != null ? interceptedResult : handler.shouldRefreshCache(options, cacheEntry);
|
|
845
|
-
} : (options, cacheEntry) => handler.shouldRefreshCache(options, cacheEntry);
|
|
846
|
-
return {
|
|
847
|
-
fulfillRequest: fulfillRequestFn,
|
|
848
|
-
shouldRefreshCache: shouldRefreshCacheFn,
|
|
849
|
-
getKey: options => handler.getKey(options),
|
|
850
|
-
type: handler.type,
|
|
851
|
-
cache: handler.cache,
|
|
852
|
-
hydrate: handler.hydrate
|
|
853
|
-
};
|
|
854
|
-
}
|
|
855
|
-
|
|
856
|
-
_getCacheLookupFnFromInterceptor(interceptor) {
|
|
857
|
-
const getEntry = interceptor && interceptor.getEntry;
|
|
858
|
-
|
|
859
|
-
if (!getEntry) {
|
|
860
|
-
return _util_response_cache_js__WEBPACK_IMPORTED_MODULE_1__[/* ResponseCache */ "a"].Default.getEntry;
|
|
861
|
-
}
|
|
862
|
-
|
|
863
|
-
return (handler, options) => {
|
|
864
|
-
// 1. Lookup the current cache value.
|
|
865
|
-
const cacheEntry = _util_response_cache_js__WEBPACK_IMPORTED_MODULE_1__[/* ResponseCache */ "a"].Default.getEntry(handler, options); // 2. See if our interceptor wants to override it.
|
|
866
|
-
|
|
867
|
-
const interceptedData = getEntry(options, cacheEntry); // 3. Return the appropriate response.
|
|
868
|
-
|
|
869
|
-
return interceptedData != null ? interceptedData : cacheEntry;
|
|
870
|
-
};
|
|
871
|
-
}
|
|
872
|
-
|
|
873
|
-
render() {
|
|
874
|
-
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_intercept_context_js__WEBPACK_IMPORTED_MODULE_3__[/* default */ "a"].Consumer, null, value => {
|
|
875
|
-
const handlerType = this.props.handler.type;
|
|
876
|
-
const interceptor = value[handlerType];
|
|
877
|
-
|
|
878
|
-
const handler = this._getHandlerFromInterceptor(interceptor);
|
|
879
|
-
|
|
880
|
-
const getEntry = this._getCacheLookupFnFromInterceptor(interceptor);
|
|
881
|
-
/**
|
|
882
|
-
* Need to share our types with InternalData so Flow
|
|
883
|
-
* doesn't need to infer them and find mismatches.
|
|
884
|
-
* However, just deriving a new component creates issues
|
|
885
|
-
* where InternalData starts rerendering too often.
|
|
886
|
-
* Couldn't track down why, so suppressing the error
|
|
887
|
-
* instead.
|
|
888
|
-
*/
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_internal_data_js__WEBPACK_IMPORTED_MODULE_2__[/* default */ "a"] // $FlowIgnore[incompatible-type-arg]
|
|
892
|
-
, {
|
|
893
|
-
handler: handler,
|
|
894
|
-
options: this.props.options,
|
|
895
|
-
getEntry: getEntry
|
|
896
|
-
}, result => this.props.children(result));
|
|
897
|
-
});
|
|
898
|
-
}
|
|
857
|
+
const Data = props => {
|
|
858
|
+
const data = Object(_hooks_use_data_js__WEBPACK_IMPORTED_MODULE_1__[/* useData */ "a"])(props.handler, props.options);
|
|
859
|
+
return props.children(data);
|
|
860
|
+
};
|
|
899
861
|
|
|
900
|
-
|
|
862
|
+
/* harmony default export */ __webpack_exports__["a"] = (Data);
|
|
901
863
|
|
|
902
864
|
/***/ }),
|
|
903
865
|
/* 11 */
|
|
@@ -916,9 +878,6 @@ class Data extends react__WEBPACK_IMPORTED_MODULE_0__["Component"] {
|
|
|
916
878
|
* type of a given handler and provide alternative results. This is mostly
|
|
917
879
|
* useful for testing.
|
|
918
880
|
*
|
|
919
|
-
* Results from this interceptor will end up in the cache. If you
|
|
920
|
-
* wish to only override the cache, use `InterceptCache` instead.
|
|
921
|
-
*
|
|
922
881
|
* This component is not recommended for use in production code as it
|
|
923
882
|
* can prevent predictable functioning of the Wonder Blocks Data framework.
|
|
924
883
|
* One possible side-effect is that inflight requests from the interceptor could
|
|
@@ -935,8 +894,7 @@ class InterceptData extends react__WEBPACK_IMPORTED_MODULE_0__["Component"] {
|
|
|
935
894
|
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_intercept_context_js__WEBPACK_IMPORTED_MODULE_1__[/* default */ "a"].Consumer, null, value => {
|
|
936
895
|
const handlerType = this.props.handler.type;
|
|
937
896
|
const interceptor = { ...value[handlerType],
|
|
938
|
-
fulfillRequest: this.props.fulfillRequest
|
|
939
|
-
shouldRefreshCache: this.props.shouldRefreshCache || null
|
|
897
|
+
fulfillRequest: this.props.fulfillRequest
|
|
940
898
|
};
|
|
941
899
|
const newValue = { ...value,
|
|
942
900
|
[handlerType]: interceptor
|
|
@@ -954,248 +912,46 @@ class InterceptData extends react__WEBPACK_IMPORTED_MODULE_0__["Component"] {
|
|
|
954
912
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
955
913
|
|
|
956
914
|
"use strict";
|
|
957
|
-
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return
|
|
958
|
-
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0);
|
|
959
|
-
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
|
|
960
|
-
/* harmony import */ var _intercept_context_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(4);
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
/**
|
|
965
|
-
* This component provides a mechanism to intercept cache lookups for the
|
|
966
|
-
* type of a given handler and provide alternative values. This is mostly
|
|
967
|
-
* useful for testing.
|
|
968
|
-
*
|
|
969
|
-
* This does not modify the cache in any way. If you want to intercept
|
|
970
|
-
* requests and cache based on the intercept, then use `InterceptData`.
|
|
971
|
-
*
|
|
972
|
-
* This component is generally not suitable for use in production code as it
|
|
973
|
-
* can prevent predictable functioning of the Wonder Blocks Data framework.
|
|
974
|
-
*
|
|
975
|
-
* These components do not chain. If a different `InterceptCache` instance is
|
|
976
|
-
* rendered within this one that intercepts the same handler type, then that
|
|
977
|
-
* new instance will replace this interceptor for its children.
|
|
978
|
-
*/
|
|
979
|
-
class InterceptCache extends react__WEBPACK_IMPORTED_MODULE_0__["Component"] {
|
|
980
|
-
render() {
|
|
981
|
-
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_intercept_context_js__WEBPACK_IMPORTED_MODULE_1__[/* default */ "a"].Consumer, null, value => {
|
|
982
|
-
const handlerType = this.props.handler.type;
|
|
983
|
-
const interceptor = { ...value[handlerType],
|
|
984
|
-
getEntry: this.props.getEntry
|
|
985
|
-
};
|
|
986
|
-
const newValue = { ...value,
|
|
987
|
-
[handlerType]: interceptor
|
|
988
|
-
};
|
|
989
|
-
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_intercept_context_js__WEBPACK_IMPORTED_MODULE_1__[/* default */ "a"].Provider, {
|
|
990
|
-
value: newValue
|
|
991
|
-
}, this.props.children);
|
|
992
|
-
});
|
|
993
|
-
}
|
|
994
|
-
|
|
995
|
-
}
|
|
996
|
-
|
|
997
|
-
/***/ }),
|
|
998
|
-
/* 13 */
|
|
999
|
-
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
1000
|
-
|
|
1001
|
-
"use strict";
|
|
1002
|
-
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return InternalData; });
|
|
1003
|
-
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0);
|
|
1004
|
-
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
|
|
1005
|
-
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2);
|
|
1006
|
-
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_1__);
|
|
1007
|
-
/* harmony import */ var _util_request_fulfillment_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6);
|
|
1008
|
-
/* harmony import */ var _util_request_tracking_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(3);
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
915
|
+
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return resultFromCacheEntry; });
|
|
1014
916
|
/**
|
|
1015
|
-
*
|
|
1016
|
-
* It is wrapped by Data in order to support intercepts and be exported for use.
|
|
1017
|
-
*
|
|
1018
|
-
* INTERNAL USE ONLY
|
|
917
|
+
* Turns a cache entry into a stateful result.
|
|
1019
918
|
*/
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
this.state = this._buildStateAndfulfillNeeds(props);
|
|
1024
|
-
}
|
|
1025
|
-
|
|
1026
|
-
componentDidMount() {
|
|
1027
|
-
this._mounted = true;
|
|
1028
|
-
}
|
|
1029
|
-
|
|
1030
|
-
shouldComponentUpdate(nextProps, nextState) {
|
|
1031
|
-
/**
|
|
1032
|
-
* We only bother updating if our state changed.
|
|
1033
|
-
*
|
|
1034
|
-
* And we only update the state if props changed
|
|
1035
|
-
* or we got new data/error.
|
|
1036
|
-
*/
|
|
1037
|
-
if (!this._propsMatch(nextProps)) {
|
|
1038
|
-
const newState = this._buildStateAndfulfillNeeds(nextProps);
|
|
1039
|
-
|
|
1040
|
-
this.setState(newState);
|
|
1041
|
-
}
|
|
1042
|
-
|
|
1043
|
-
return this.state.loading !== nextState.loading || this.state.data !== nextState.data || this.state.error !== nextState.error;
|
|
1044
|
-
}
|
|
1045
|
-
|
|
1046
|
-
componentWillUnmount() {
|
|
1047
|
-
this._mounted = false;
|
|
1048
|
-
}
|
|
1049
|
-
|
|
1050
|
-
_propsMatch(otherProps) {
|
|
1051
|
-
const {
|
|
1052
|
-
handler,
|
|
1053
|
-
options
|
|
1054
|
-
} = this.props;
|
|
1055
|
-
const {
|
|
1056
|
-
handler: prevHandler,
|
|
1057
|
-
options: prevOptions
|
|
1058
|
-
} = otherProps;
|
|
1059
|
-
return handler === prevHandler && handler.getKey(options) === prevHandler.getKey(prevOptions);
|
|
1060
|
-
}
|
|
1061
|
-
|
|
1062
|
-
_buildStateAndfulfillNeeds(propsAtFulfillment) {
|
|
1063
|
-
const {
|
|
1064
|
-
getEntry,
|
|
1065
|
-
handler,
|
|
1066
|
-
options
|
|
1067
|
-
} = propsAtFulfillment;
|
|
1068
|
-
const cachedData = getEntry(handler, options);
|
|
1069
|
-
|
|
1070
|
-
if (!_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_1__["Server"].isServerSide() && (cachedData == null || handler.shouldRefreshCache(options, cachedData))) {
|
|
1071
|
-
/**
|
|
1072
|
-
* We're not on the server, the cache missed, or our handler says
|
|
1073
|
-
* we should refresh the cache.
|
|
1074
|
-
*
|
|
1075
|
-
* Therefore, we need to request data.
|
|
1076
|
-
*
|
|
1077
|
-
* We have to do this here from the constructor so that this
|
|
1078
|
-
* data request is tracked when performing server-side rendering.
|
|
1079
|
-
*/
|
|
1080
|
-
_util_request_fulfillment_js__WEBPACK_IMPORTED_MODULE_2__[/* RequestFulfillment */ "a"].Default.fulfill(handler, options).then(cacheEntry => {
|
|
1081
|
-
/**
|
|
1082
|
-
* We get here, we should have updated the cache.
|
|
1083
|
-
* However, we need to update the component, but we
|
|
1084
|
-
* should only do that if the props are the same as they
|
|
1085
|
-
* were when this was called.
|
|
1086
|
-
*/
|
|
1087
|
-
if (this._mounted && this._propsMatch(propsAtFulfillment)) {
|
|
1088
|
-
this.setState({
|
|
1089
|
-
loading: false,
|
|
1090
|
-
data: cacheEntry.data,
|
|
1091
|
-
error: cacheEntry.error
|
|
1092
|
-
});
|
|
1093
|
-
}
|
|
1094
|
-
|
|
1095
|
-
return null;
|
|
1096
|
-
}).catch(e => {
|
|
1097
|
-
/**
|
|
1098
|
-
* We should never get here, but if we do.
|
|
1099
|
-
*/
|
|
1100
|
-
// eslint-disable-next-line no-console
|
|
1101
|
-
console.error(`Unexpected error occurred during data fulfillment: ${e}`);
|
|
1102
|
-
|
|
1103
|
-
if (this._mounted && this._propsMatch(propsAtFulfillment)) {
|
|
1104
|
-
this.setState({
|
|
1105
|
-
loading: false,
|
|
1106
|
-
data: null,
|
|
1107
|
-
error: typeof e === "string" ? e : e.message
|
|
1108
|
-
});
|
|
1109
|
-
}
|
|
1110
|
-
|
|
1111
|
-
return null;
|
|
1112
|
-
});
|
|
1113
|
-
}
|
|
1114
|
-
/**
|
|
1115
|
-
* This is the default response for the server and for the initial
|
|
1116
|
-
* client-side render if we have cachedData.
|
|
1117
|
-
*
|
|
1118
|
-
* This ensures we don't make promises we don't want when doing
|
|
1119
|
-
* server-side rendering. Instead, we either have data from the cache
|
|
1120
|
-
* or we don't.
|
|
1121
|
-
*/
|
|
1122
|
-
|
|
1123
|
-
|
|
919
|
+
const resultFromCacheEntry = cacheEntry => {
|
|
920
|
+
// No cache entry means we didn't load one yet.
|
|
921
|
+
if (cacheEntry == null) {
|
|
1124
922
|
return {
|
|
1125
|
-
|
|
1126
|
-
data: cachedData && cachedData.data,
|
|
1127
|
-
error: cachedData && cachedData.error
|
|
923
|
+
status: "loading"
|
|
1128
924
|
};
|
|
1129
925
|
}
|
|
1130
926
|
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
error
|
|
1136
|
-
} = this.state;
|
|
1137
|
-
|
|
1138
|
-
if (loading) {
|
|
1139
|
-
return {
|
|
1140
|
-
loading: true
|
|
1141
|
-
};
|
|
1142
|
-
}
|
|
1143
|
-
|
|
1144
|
-
if (data != null) {
|
|
1145
|
-
return {
|
|
1146
|
-
loading: false,
|
|
1147
|
-
data
|
|
1148
|
-
};
|
|
1149
|
-
}
|
|
1150
|
-
|
|
1151
|
-
if (error == null) {
|
|
1152
|
-
// We should never get here ever.
|
|
1153
|
-
throw new Error("Loaded result has invalid state where data and error are missing");
|
|
1154
|
-
}
|
|
927
|
+
const {
|
|
928
|
+
data,
|
|
929
|
+
error
|
|
930
|
+
} = cacheEntry;
|
|
1155
931
|
|
|
932
|
+
if (data != null) {
|
|
1156
933
|
return {
|
|
1157
|
-
|
|
1158
|
-
|
|
934
|
+
status: "success",
|
|
935
|
+
data
|
|
1159
936
|
};
|
|
1160
937
|
}
|
|
1161
938
|
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
_renderWithTrackingContext(result) {
|
|
1170
|
-
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_util_request_tracking_js__WEBPACK_IMPORTED_MODULE_3__[/* TrackerContext */ "b"].Consumer, null, track => {
|
|
1171
|
-
/**
|
|
1172
|
-
* If data tracking wasn't enabled, don't do it.
|
|
1173
|
-
*/
|
|
1174
|
-
if (track != null) {
|
|
1175
|
-
track(this.props.handler, this.props.options);
|
|
1176
|
-
}
|
|
1177
|
-
|
|
1178
|
-
return this._renderContent(result);
|
|
1179
|
-
});
|
|
1180
|
-
}
|
|
1181
|
-
|
|
1182
|
-
render() {
|
|
1183
|
-
const result = this._resultFromState(); // We only track data requests when we are server-side and we don't
|
|
1184
|
-
// already have a result. The existence of a result is indicated by the
|
|
1185
|
-
// loading flag being false.
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
if (result.loading && _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_1__["Server"].isServerSide()) {
|
|
1189
|
-
return this._renderWithTrackingContext(result);
|
|
1190
|
-
}
|
|
1191
|
-
|
|
1192
|
-
return this._renderContent(result);
|
|
939
|
+
if (error == null) {
|
|
940
|
+
// We should never get here ever.
|
|
941
|
+
return {
|
|
942
|
+
status: "error",
|
|
943
|
+
error: "Loaded result has invalid state where data and error are missing"
|
|
944
|
+
};
|
|
1193
945
|
}
|
|
1194
946
|
|
|
1195
|
-
|
|
947
|
+
return {
|
|
948
|
+
status: "error",
|
|
949
|
+
error
|
|
950
|
+
};
|
|
951
|
+
};
|
|
1196
952
|
|
|
1197
953
|
/***/ }),
|
|
1198
|
-
/*
|
|
954
|
+
/* 13 */
|
|
1199
955
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
1200
956
|
|
|
1201
957
|
"use strict";
|
|
@@ -1205,9 +961,9 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
1205
961
|
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "hasUnfulfilledRequests", function() { return hasUnfulfilledRequests; });
|
|
1206
962
|
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "removeFromCache", function() { return removeFromCache; });
|
|
1207
963
|
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "removeAllFromCache", function() { return removeAllFromCache; });
|
|
1208
|
-
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(
|
|
964
|
+
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
|
|
1209
965
|
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__);
|
|
1210
|
-
/* harmony import */ var _util_response_cache_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(
|
|
966
|
+
/* harmony import */ var _util_response_cache_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2);
|
|
1211
967
|
/* harmony import */ var _util_request_tracking_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(3);
|
|
1212
968
|
/* harmony import */ var _util_request_handler_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(8);
|
|
1213
969
|
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "RequestHandler", function() { return _util_request_handler_js__WEBPACK_IMPORTED_MODULE_3__["a"]; });
|
|
@@ -1221,11 +977,8 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
1221
977
|
/* harmony import */ var _components_intercept_data_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(11);
|
|
1222
978
|
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "InterceptData", function() { return _components_intercept_data_js__WEBPACK_IMPORTED_MODULE_6__["a"]; });
|
|
1223
979
|
|
|
1224
|
-
/* harmony import */ var
|
|
1225
|
-
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "
|
|
1226
|
-
|
|
1227
|
-
/* harmony import */ var _util_no_cache_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(5);
|
|
1228
|
-
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "NoCache", function() { return _util_no_cache_js__WEBPACK_IMPORTED_MODULE_8__["a"]; });
|
|
980
|
+
/* harmony import */ var _hooks_use_data_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(5);
|
|
981
|
+
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "useData", function() { return _hooks_use_data_js__WEBPACK_IMPORTED_MODULE_7__["a"]; });
|
|
1229
982
|
|
|
1230
983
|
|
|
1231
984
|
|
|
@@ -1259,6 +1012,5 @@ const removeAllFromCache = (handler, predicate) => _util_response_cache_js__WEBP
|
|
|
1259
1012
|
|
|
1260
1013
|
|
|
1261
1014
|
|
|
1262
|
-
|
|
1263
1015
|
/***/ })
|
|
1264
1016
|
/******/ ]);
|