index.mjs 44 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034
  1. import { useEffect, useLayoutEffect, createContext, useContext, useState, createElement, useRef, useCallback, useDebugValue } from 'react';
  2. /*! *****************************************************************************
  3. Copyright (c) Microsoft Corporation.
  4. Permission to use, copy, modify, and/or distribute this software for any
  5. purpose with or without fee is hereby granted.
  6. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
  7. REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  8. AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
  9. INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  10. LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  11. OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  12. PERFORMANCE OF THIS SOFTWARE.
  13. ***************************************************************************** */
  14. function __awaiter(thisArg, _arguments, P, generator) {
  15. function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
  16. return new (P || (P = Promise))(function (resolve, reject) {
  17. function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
  18. function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
  19. function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
  20. step((generator = generator.apply(thisArg, _arguments || [])).next());
  21. });
  22. }
  23. function __generator(thisArg, body) {
  24. var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
  25. return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
  26. function verb(n) { return function (v) { return step([n, v]); }; }
  27. function step(op) {
  28. if (f) throw new TypeError("Generator is already executing.");
  29. while (_) try {
  30. if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
  31. if (y = 0, t) op = [op[0] & 2, t.value];
  32. switch (op[0]) {
  33. case 0: case 1: t = op; break;
  34. case 4: _.label++; return { value: op[1], done: false };
  35. case 5: _.label++; y = op[1]; op = [0]; continue;
  36. case 7: op = _.ops.pop(); _.trys.pop(); continue;
  37. default:
  38. if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
  39. if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
  40. if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
  41. if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
  42. if (t[2]) _.ops.pop();
  43. _.trys.pop(); continue;
  44. }
  45. op = body.call(thisArg, _);
  46. } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
  47. if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
  48. }
  49. }
  50. var noop = function () { };
  51. // Using noop() as the undefined value as undefined can possibly be replaced
  52. // by something else. Prettier ignore and extra parentheses are necessary here
  53. // to ensure that tsc doesn't remove the __NOINLINE__ comment.
  54. // prettier-ignore
  55. var UNDEFINED = ( /*#__NOINLINE__*/noop());
  56. var OBJECT = Object;
  57. var isUndefined = function (v) { return v === UNDEFINED; };
  58. var isFunction = function (v) { return typeof v == 'function'; };
  59. var mergeObjects = function (a, b) { return OBJECT.assign({}, a, b); };
  60. var STR_UNDEFINED = 'undefined';
  61. // NOTE: Use function to guarantee it's re-evaluated between jsdom and node runtime for tests.
  62. var hasWindow = function () { return typeof window != STR_UNDEFINED; };
  63. var hasDocument = function () { return typeof document != STR_UNDEFINED; };
  64. var hasRequestAnimationFrame = function () {
  65. return hasWindow() && typeof window['requestAnimationFrame'] != STR_UNDEFINED;
  66. };
  67. // use WeakMap to store the object->key mapping
  68. // so the objects can be garbage collected.
  69. // WeakMap uses a hashtable under the hood, so the lookup
  70. // complexity is almost O(1).
  71. var table = new WeakMap();
  72. // counter of the key
  73. var counter = 0;
  74. // A stable hash implementation that supports:
  75. // - Fast and ensures unique hash properties
  76. // - Handles unserializable values
  77. // - Handles object key ordering
  78. // - Generates short results
  79. //
  80. // This is not a serialization function, and the result is not guaranteed to be
  81. // parsible.
  82. var stableHash = function (arg) {
  83. var type = typeof arg;
  84. var constructor = arg && arg.constructor;
  85. var isDate = constructor == Date;
  86. var result;
  87. var index;
  88. if (OBJECT(arg) === arg && !isDate && constructor != RegExp) {
  89. // Object/function, not null/date/regexp. Use WeakMap to store the id first.
  90. // If it's already hashed, directly return the result.
  91. result = table.get(arg);
  92. if (result)
  93. return result;
  94. // Store the hash first for circular reference detection before entering the
  95. // recursive `stableHash` calls.
  96. // For other objects like set and map, we use this id directly as the hash.
  97. result = ++counter + '~';
  98. table.set(arg, result);
  99. if (constructor == Array) {
  100. // Array.
  101. result = '@';
  102. for (index = 0; index < arg.length; index++) {
  103. result += stableHash(arg[index]) + ',';
  104. }
  105. table.set(arg, result);
  106. }
  107. if (constructor == OBJECT) {
  108. // Object, sort keys.
  109. result = '#';
  110. var keys = OBJECT.keys(arg).sort();
  111. while (!isUndefined((index = keys.pop()))) {
  112. if (!isUndefined(arg[index])) {
  113. result += index + ':' + stableHash(arg[index]) + ',';
  114. }
  115. }
  116. table.set(arg, result);
  117. }
  118. }
  119. else {
  120. result = isDate
  121. ? arg.toJSON()
  122. : type == 'symbol'
  123. ? arg.toString()
  124. : type == 'string'
  125. ? JSON.stringify(arg)
  126. : '' + arg;
  127. }
  128. return result;
  129. };
  130. /**
  131. * Due to bug https://bugs.chromium.org/p/chromium/issues/detail?id=678075,
  132. * it's not reliable to detect if the browser is currently online or offline
  133. * based on `navigator.onLine`.
  134. * As a work around, we always assume it's online on first load, and change
  135. * the status upon `online` or `offline` events.
  136. */
  137. var online = true;
  138. var isOnline = function () { return online; };
  139. var hasWin = hasWindow();
  140. var hasDoc = hasDocument();
  141. // For node and React Native, `add/removeEventListener` doesn't exist on window.
  142. var onWindowEvent = hasWin && window.addEventListener
  143. ? window.addEventListener.bind(window)
  144. : noop;
  145. var onDocumentEvent = hasDoc ? document.addEventListener.bind(document) : noop;
  146. var offWindowEvent = hasWin && window.removeEventListener
  147. ? window.removeEventListener.bind(window)
  148. : noop;
  149. var offDocumentEvent = hasDoc
  150. ? document.removeEventListener.bind(document)
  151. : noop;
  152. var isVisible = function () {
  153. var visibilityState = hasDoc && document.visibilityState;
  154. return isUndefined(visibilityState) || visibilityState !== 'hidden';
  155. };
  156. var initFocus = function (callback) {
  157. // focus revalidate
  158. onDocumentEvent('visibilitychange', callback);
  159. onWindowEvent('focus', callback);
  160. return function () {
  161. offDocumentEvent('visibilitychange', callback);
  162. offWindowEvent('focus', callback);
  163. };
  164. };
  165. var initReconnect = function (callback) {
  166. // revalidate on reconnected
  167. var onOnline = function () {
  168. online = true;
  169. callback();
  170. };
  171. // nothing to revalidate, just update the status
  172. var onOffline = function () {
  173. online = false;
  174. };
  175. onWindowEvent('online', onOnline);
  176. onWindowEvent('offline', onOffline);
  177. return function () {
  178. offWindowEvent('online', onOnline);
  179. offWindowEvent('offline', onOffline);
  180. };
  181. };
  182. var preset = {
  183. isOnline: isOnline,
  184. isVisible: isVisible
  185. };
  186. var defaultConfigOptions = {
  187. initFocus: initFocus,
  188. initReconnect: initReconnect
  189. };
  190. var IS_SERVER = !hasWindow() || 'Deno' in window;
  191. // Polyfill requestAnimationFrame
  192. var rAF = function (f) {
  193. return hasRequestAnimationFrame() ? window['requestAnimationFrame'](f) : setTimeout(f, 1);
  194. };
  195. // React currently throws a warning when using useLayoutEffect on the server.
  196. // To get around it, we can conditionally useEffect on the server (no-op) and
  197. // useLayoutEffect in the browser.
  198. var useIsomorphicLayoutEffect = IS_SERVER ? useEffect : useLayoutEffect;
  199. // This assignment is to extend the Navigator type to use effectiveType.
  200. var navigatorConnection = typeof navigator !== 'undefined' &&
  201. navigator.connection;
  202. // Adjust the config based on slow connection status (<= 70Kbps).
  203. var slowConnection = !IS_SERVER &&
  204. navigatorConnection &&
  205. (['slow-2g', '2g'].includes(navigatorConnection.effectiveType) ||
  206. navigatorConnection.saveData);
  207. var serialize = function (key) {
  208. if (isFunction(key)) {
  209. try {
  210. key = key();
  211. }
  212. catch (err) {
  213. // dependencies not ready
  214. key = '';
  215. }
  216. }
  217. var args = [].concat(key);
  218. // If key is not falsy, or not an empty array, hash it.
  219. key =
  220. typeof key == 'string'
  221. ? key
  222. : (Array.isArray(key) ? key.length : key)
  223. ? stableHash(key)
  224. : '';
  225. var infoKey = key ? '$swr$' + key : '';
  226. return [key, args, infoKey];
  227. };
  228. // Global state used to deduplicate requests and store listeners
  229. var SWRGlobalState = new WeakMap();
  230. var FOCUS_EVENT = 0;
  231. var RECONNECT_EVENT = 1;
  232. var MUTATE_EVENT = 2;
  233. var broadcastState = function (cache, key, data, error, isValidating, revalidate, broadcast) {
  234. if (broadcast === void 0) { broadcast = true; }
  235. var _a = SWRGlobalState.get(cache), EVENT_REVALIDATORS = _a[0], STATE_UPDATERS = _a[1], FETCH = _a[3];
  236. var revalidators = EVENT_REVALIDATORS[key];
  237. var updaters = STATE_UPDATERS[key];
  238. // Cache was populated, update states of all hooks.
  239. if (broadcast && updaters) {
  240. for (var i = 0; i < updaters.length; ++i) {
  241. updaters[i](data, error, isValidating);
  242. }
  243. }
  244. // If we also need to revalidate, only do it for the first hook.
  245. if (revalidate) {
  246. // Invalidate the key by deleting the concurrent request markers so new
  247. // requests will not be deduped.
  248. delete FETCH[key];
  249. if (revalidators && revalidators[0]) {
  250. return revalidators[0](MUTATE_EVENT).then(function () {
  251. return cache.get(key);
  252. });
  253. }
  254. }
  255. return cache.get(key);
  256. };
  257. // Global timestamp.
  258. var __timestamp = 0;
  259. var getTimestamp = function () { return ++__timestamp; };
  260. var internalMutate = function () {
  261. var args = [];
  262. for (var _i = 0; _i < arguments.length; _i++) {
  263. args[_i] = arguments[_i];
  264. }
  265. return __awaiter(void 0, void 0, void 0, function () {
  266. var cache, _key, _data, _opts, options, populateCache, revalidate, rollbackOnError, optimisticData, _a, key, keyInfo, _b, MUTATION, data, error, beforeMutationTs, hasOptimisticData, rollbackData, res;
  267. return __generator(this, function (_c) {
  268. switch (_c.label) {
  269. case 0:
  270. cache = args[0], _key = args[1], _data = args[2], _opts = args[3];
  271. options = typeof _opts === 'boolean' ? { revalidate: _opts } : _opts || {};
  272. populateCache = options.populateCache !== false;
  273. revalidate = options.revalidate !== false;
  274. rollbackOnError = options.rollbackOnError !== false;
  275. optimisticData = options.optimisticData;
  276. _a = serialize(_key), key = _a[0], keyInfo = _a[2];
  277. if (!key)
  278. return [2 /*return*/];
  279. _b = SWRGlobalState.get(cache), MUTATION = _b[2];
  280. // If there is no new data provided, revalidate the key with current state.
  281. if (args.length < 3) {
  282. // Revalidate and broadcast state.
  283. return [2 /*return*/, broadcastState(cache, key, cache.get(key), UNDEFINED, UNDEFINED, revalidate, populateCache)];
  284. }
  285. data = _data;
  286. beforeMutationTs = getTimestamp();
  287. MUTATION[key] = [beforeMutationTs, 0];
  288. hasOptimisticData = !isUndefined(optimisticData);
  289. rollbackData = cache.get(key);
  290. // Do optimistic data update.
  291. if (hasOptimisticData) {
  292. cache.set(key, optimisticData);
  293. broadcastState(cache, key, optimisticData);
  294. }
  295. if (isFunction(data)) {
  296. // `data` is a function, call it passing current cache value.
  297. try {
  298. data = data(cache.get(key));
  299. }
  300. catch (err) {
  301. // If it throws an error synchronously, we shouldn't update the cache.
  302. error = err;
  303. }
  304. }
  305. if (!(data && isFunction(data.then))) return [3 /*break*/, 2];
  306. return [4 /*yield*/, data.catch(function (err) {
  307. error = err;
  308. })
  309. // Check if other mutations have occurred since we've started this mutation.
  310. // If there's a race we don't update cache or broadcast the change,
  311. // just return the data.
  312. ];
  313. case 1:
  314. // This means that the mutation is async, we need to check timestamps to
  315. // avoid race conditions.
  316. data = _c.sent();
  317. // Check if other mutations have occurred since we've started this mutation.
  318. // If there's a race we don't update cache or broadcast the change,
  319. // just return the data.
  320. if (beforeMutationTs !== MUTATION[key][0]) {
  321. if (error)
  322. throw error;
  323. return [2 /*return*/, data];
  324. }
  325. else if (error && hasOptimisticData && rollbackOnError) {
  326. // Rollback. Always populate the cache in this case.
  327. populateCache = true;
  328. data = rollbackData;
  329. cache.set(key, rollbackData);
  330. }
  331. _c.label = 2;
  332. case 2:
  333. if (populateCache) {
  334. if (!error) {
  335. // Only update cached data if there's no error. Data can be `undefined` here.
  336. cache.set(key, data);
  337. }
  338. // Always update or reset the error.
  339. cache.set(keyInfo, mergeObjects(cache.get(keyInfo), { error: error }));
  340. }
  341. // Reset the timestamp to mark the mutation has ended.
  342. MUTATION[key][1] = getTimestamp();
  343. return [4 /*yield*/, broadcastState(cache, key, data, error, UNDEFINED, revalidate, populateCache)
  344. // Throw error or return data
  345. ];
  346. case 3:
  347. res = _c.sent();
  348. // Throw error or return data
  349. if (error)
  350. throw error;
  351. return [2 /*return*/, populateCache ? res : data];
  352. }
  353. });
  354. });
  355. };
  356. var revalidateAllKeys = function (revalidators, type) {
  357. for (var key in revalidators) {
  358. if (revalidators[key][0])
  359. revalidators[key][0](type);
  360. }
  361. };
  362. var initCache = function (provider, options) {
  363. // The global state for a specific provider will be used to deduplicate
  364. // requests and store listeners. As well as a mutate function that bound to
  365. // the cache.
  366. // Provider's global state might be already initialized. Let's try to get the
  367. // global state associated with the provider first.
  368. if (!SWRGlobalState.has(provider)) {
  369. var opts = mergeObjects(defaultConfigOptions, options);
  370. // If there's no global state bound to the provider, create a new one with the
  371. // new mutate function.
  372. var EVENT_REVALIDATORS = {};
  373. var mutate = internalMutate.bind(UNDEFINED, provider);
  374. var unmount = noop;
  375. // Update the state if it's new, or the provider has been extended.
  376. SWRGlobalState.set(provider, [EVENT_REVALIDATORS, {}, {}, {}, mutate]);
  377. // This is a new provider, we need to initialize it and setup DOM events
  378. // listeners for `focus` and `reconnect` actions.
  379. if (!IS_SERVER) {
  380. // When listening to the native events for auto revalidations,
  381. // we intentionally put a delay (setTimeout) here to make sure they are
  382. // fired after immediate JavaScript executions, which can possibly be
  383. // React's state updates.
  384. // This avoids some unnecessary revalidations such as
  385. // https://github.com/vercel/swr/issues/1680.
  386. var releaseFocus_1 = opts.initFocus(setTimeout.bind(UNDEFINED, revalidateAllKeys.bind(UNDEFINED, EVENT_REVALIDATORS, FOCUS_EVENT)));
  387. var releaseReconnect_1 = opts.initReconnect(setTimeout.bind(UNDEFINED, revalidateAllKeys.bind(UNDEFINED, EVENT_REVALIDATORS, RECONNECT_EVENT)));
  388. unmount = function () {
  389. releaseFocus_1 && releaseFocus_1();
  390. releaseReconnect_1 && releaseReconnect_1();
  391. // When un-mounting, we need to remove the cache provider from the state
  392. // storage too because it's a side-effect. Otherwise when re-mounting we
  393. // will not re-register those event listeners.
  394. SWRGlobalState.delete(provider);
  395. };
  396. }
  397. // We might want to inject an extra layer on top of `provider` in the future,
  398. // such as key serialization, auto GC, etc.
  399. // For now, it's just a `Map` interface without any modifications.
  400. return [provider, mutate, unmount];
  401. }
  402. return [provider, SWRGlobalState.get(provider)[4]];
  403. };
  404. // error retry
  405. var onErrorRetry = function (_, __, config, revalidate, opts) {
  406. var maxRetryCount = config.errorRetryCount;
  407. var currentRetryCount = opts.retryCount;
  408. // Exponential backoff
  409. var timeout = ~~((Math.random() + 0.5) *
  410. (1 << (currentRetryCount < 8 ? currentRetryCount : 8))) * config.errorRetryInterval;
  411. if (!isUndefined(maxRetryCount) && currentRetryCount > maxRetryCount) {
  412. return;
  413. }
  414. setTimeout(revalidate, timeout, opts);
  415. };
  416. // Default cache provider
  417. var _a = initCache(new Map()), cache = _a[0], mutate = _a[1];
  418. // Default config
  419. var defaultConfig = mergeObjects({
  420. // events
  421. onLoadingSlow: noop,
  422. onSuccess: noop,
  423. onError: noop,
  424. onErrorRetry: onErrorRetry,
  425. onDiscarded: noop,
  426. // switches
  427. revalidateOnFocus: true,
  428. revalidateOnReconnect: true,
  429. revalidateIfStale: true,
  430. shouldRetryOnError: true,
  431. // timeouts
  432. errorRetryInterval: slowConnection ? 10000 : 5000,
  433. focusThrottleInterval: 5 * 1000,
  434. dedupingInterval: 2 * 1000,
  435. loadingTimeout: slowConnection ? 5000 : 3000,
  436. // providers
  437. compare: function (currentData, newData) {
  438. return stableHash(currentData) == stableHash(newData);
  439. },
  440. isPaused: function () { return false; },
  441. cache: cache,
  442. mutate: mutate,
  443. fallback: {}
  444. },
  445. // use web preset by default
  446. preset);
  447. var mergeConfigs = function (a, b) {
  448. // Need to create a new object to avoid mutating the original here.
  449. var v = mergeObjects(a, b);
  450. // If two configs are provided, merge their `use` and `fallback` options.
  451. if (b) {
  452. var u1 = a.use, f1 = a.fallback;
  453. var u2 = b.use, f2 = b.fallback;
  454. if (u1 && u2) {
  455. v.use = u1.concat(u2);
  456. }
  457. if (f1 && f2) {
  458. v.fallback = mergeObjects(f1, f2);
  459. }
  460. }
  461. return v;
  462. };
  463. var SWRConfigContext = createContext({});
  464. var SWRConfig$1 = function (props) {
  465. var value = props.value;
  466. // Extend parent context values and middleware.
  467. var extendedConfig = mergeConfigs(useContext(SWRConfigContext), value);
  468. // Should not use the inherited provider.
  469. var provider = value && value.provider;
  470. // Use a lazy initialized state to create the cache on first access.
  471. var cacheContext = useState(function () {
  472. return provider
  473. ? initCache(provider(extendedConfig.cache || cache), value)
  474. : UNDEFINED;
  475. })[0];
  476. // Override the cache if a new provider is given.
  477. if (cacheContext) {
  478. extendedConfig.cache = cacheContext[0];
  479. extendedConfig.mutate = cacheContext[1];
  480. }
  481. // Unsubscribe events.
  482. useIsomorphicLayoutEffect(function () { return (cacheContext ? cacheContext[2] : UNDEFINED); }, []);
  483. return createElement(SWRConfigContext.Provider, mergeObjects(props, {
  484. value: extendedConfig
  485. }));
  486. };
  487. /**
  488. * An implementation of state with dependency-tracking.
  489. */
  490. var useStateWithDeps = function (state, unmountedRef) {
  491. var rerender = useState({})[1];
  492. var stateRef = useRef(state);
  493. // If a state property (data, error or isValidating) is accessed by the render
  494. // function, we mark the property as a dependency so if it is updated again
  495. // in the future, we trigger a rerender.
  496. // This is also known as dependency-tracking.
  497. var stateDependenciesRef = useRef({
  498. data: false,
  499. error: false,
  500. isValidating: false
  501. });
  502. /**
  503. * @param payload To change stateRef, pass the values explicitly to setState:
  504. * @example
  505. * ```js
  506. * setState({
  507. * isValidating: false
  508. * data: newData // set data to newData
  509. * error: undefined // set error to undefined
  510. * })
  511. *
  512. * setState({
  513. * isValidating: false
  514. * data: undefined // set data to undefined
  515. * error: err // set error to err
  516. * })
  517. * ```
  518. */
  519. var setState = useCallback(function (payload) {
  520. var shouldRerender = false;
  521. var currentState = stateRef.current;
  522. for (var _ in payload) {
  523. var k = _;
  524. // If the property has changed, update the state and mark rerender as
  525. // needed.
  526. if (currentState[k] !== payload[k]) {
  527. currentState[k] = payload[k];
  528. // If the property is accessed by the component, a rerender should be
  529. // triggered.
  530. if (stateDependenciesRef.current[k]) {
  531. shouldRerender = true;
  532. }
  533. }
  534. }
  535. if (shouldRerender && !unmountedRef.current) {
  536. rerender({});
  537. }
  538. },
  539. // config.suspense isn't allowed to change during the lifecycle
  540. // eslint-disable-next-line react-hooks/exhaustive-deps
  541. []);
  542. // Always update the state reference.
  543. useIsomorphicLayoutEffect(function () {
  544. stateRef.current = state;
  545. });
  546. return [stateRef, stateDependenciesRef.current, setState];
  547. };
  548. var normalize = function (args) {
  549. return isFunction(args[1])
  550. ? [args[0], args[1], args[2] || {}]
  551. : [args[0], null, (args[1] === null ? args[2] : args[1]) || {}];
  552. };
  553. var useSWRConfig = function () {
  554. return mergeObjects(defaultConfig, useContext(SWRConfigContext));
  555. };
  556. // It's tricky to pass generic types as parameters, so we just directly override
  557. // the types here.
  558. var withArgs = function (hook) {
  559. return function useSWRArgs() {
  560. var args = [];
  561. for (var _i = 0; _i < arguments.length; _i++) {
  562. args[_i] = arguments[_i];
  563. }
  564. // Get the default and inherited configuration.
  565. var fallbackConfig = useSWRConfig();
  566. // Normalize arguments.
  567. var _a = normalize(args), key = _a[0], fn = _a[1], _config = _a[2];
  568. // Merge configurations.
  569. var config = mergeConfigs(fallbackConfig, _config);
  570. // Apply middleware
  571. var next = hook;
  572. var use = config.use;
  573. if (use) {
  574. for (var i = use.length; i-- > 0;) {
  575. next = use[i](next);
  576. }
  577. }
  578. return next(key, fn || config.fetcher, config);
  579. };
  580. };
  581. // Add a callback function to a list of keyed callback functions and return
  582. // the unsubscribe function.
  583. var subscribeCallback = function (key, callbacks, callback) {
  584. var keyedRevalidators = callbacks[key] || (callbacks[key] = []);
  585. keyedRevalidators.push(callback);
  586. return function () {
  587. var index = keyedRevalidators.indexOf(callback);
  588. if (index >= 0) {
  589. // O(1): faster than splice
  590. keyedRevalidators[index] = keyedRevalidators[keyedRevalidators.length - 1];
  591. keyedRevalidators.pop();
  592. }
  593. };
  594. };
  595. var WITH_DEDUPE = { dedupe: true };
  596. var useSWRHandler = function (_key, fetcher, config) {
  597. var cache = config.cache, compare = config.compare, fallbackData = config.fallbackData, suspense = config.suspense, revalidateOnMount = config.revalidateOnMount, refreshInterval = config.refreshInterval, refreshWhenHidden = config.refreshWhenHidden, refreshWhenOffline = config.refreshWhenOffline;
  598. var _a = SWRGlobalState.get(cache), EVENT_REVALIDATORS = _a[0], STATE_UPDATERS = _a[1], MUTATION = _a[2], FETCH = _a[3];
  599. // `key` is the identifier of the SWR `data` state, `keyInfo` holds extra
  600. // states such as `error` and `isValidating` inside,
  601. // all of them are derived from `_key`.
  602. // `fnArgs` is an array of arguments parsed from the key, which will be passed
  603. // to the fetcher.
  604. var _b = serialize(_key), key = _b[0], fnArgs = _b[1], keyInfo = _b[2];
  605. // If it's the initial render of this hook.
  606. var initialMountedRef = useRef(false);
  607. // If the hook is unmounted already. This will be used to prevent some effects
  608. // to be called after unmounting.
  609. var unmountedRef = useRef(false);
  610. // Refs to keep the key and config.
  611. var keyRef = useRef(key);
  612. var fetcherRef = useRef(fetcher);
  613. var configRef = useRef(config);
  614. var getConfig = function () { return configRef.current; };
  615. var isActive = function () { return getConfig().isVisible() && getConfig().isOnline(); };
  616. var patchFetchInfo = function (info) {
  617. return cache.set(keyInfo, mergeObjects(cache.get(keyInfo), info));
  618. };
  619. // Get the current state that SWR should return.
  620. var cached = cache.get(key);
  621. var fallback = isUndefined(fallbackData)
  622. ? config.fallback[key]
  623. : fallbackData;
  624. var data = isUndefined(cached) ? fallback : cached;
  625. var info = cache.get(keyInfo) || {};
  626. var error = info.error;
  627. // - Suspense mode and there's stale data for the initial render.
  628. // - Not suspense mode and there is no fallback data and `revalidateIfStale` is enabled.
  629. // - `revalidateIfStale` is enabled but `data` is not defined.
  630. var shouldRevalidateOnMount = function () {
  631. // If `revalidateOnMount` is set, we take the value directly.
  632. if (!isUndefined(revalidateOnMount))
  633. return revalidateOnMount;
  634. // If it's paused, we skip revalidation.
  635. if (getConfig().isPaused())
  636. return false;
  637. return suspense
  638. ? // Under suspense mode, it will always fetch on render if there is no
  639. // stale data so no need to revalidate immediately on mount again.
  640. !isUndefined(data)
  641. : // If there is no stale data, we need to revalidate on mount;
  642. // If `revalidateIfStale` is set to true, we will always revalidate.
  643. isUndefined(data) || config.revalidateIfStale;
  644. };
  645. // Resolve the current validating state.
  646. var resolveValidating = function () {
  647. if (!key || !fetcher)
  648. return false;
  649. if (info.isValidating)
  650. return true;
  651. // If it's not mounted yet and it should revalidate on mount, revalidate.
  652. return !initialMountedRef.current && shouldRevalidateOnMount();
  653. };
  654. var isValidating = resolveValidating();
  655. var _c = useStateWithDeps({
  656. data: data,
  657. error: error,
  658. isValidating: isValidating
  659. }, unmountedRef), stateRef = _c[0], stateDependencies = _c[1], setState = _c[2];
  660. // The revalidation function is a carefully crafted wrapper of the original
  661. // `fetcher`, to correctly handle the many edge cases.
  662. var revalidate = useCallback(function (revalidateOpts) { return __awaiter(void 0, void 0, void 0, function () {
  663. var currentFetcher, newData, startAt, loading, opts, shouldStartNewRequest, isCurrentKeyMounted, cleanupState, newState, finishRequestAndUpdateState, mutationInfo, err_1;
  664. var _a;
  665. return __generator(this, function (_b) {
  666. switch (_b.label) {
  667. case 0:
  668. currentFetcher = fetcherRef.current;
  669. if (!key ||
  670. !currentFetcher ||
  671. unmountedRef.current ||
  672. getConfig().isPaused()) {
  673. return [2 /*return*/, false];
  674. }
  675. loading = true;
  676. opts = revalidateOpts || {};
  677. shouldStartNewRequest = !FETCH[key] || !opts.dedupe;
  678. isCurrentKeyMounted = function () {
  679. return !unmountedRef.current &&
  680. key === keyRef.current &&
  681. initialMountedRef.current;
  682. };
  683. cleanupState = function () {
  684. // Check if it's still the same request before deleting.
  685. var requestInfo = FETCH[key];
  686. if (requestInfo && requestInfo[1] === startAt) {
  687. delete FETCH[key];
  688. }
  689. };
  690. newState = { isValidating: false };
  691. finishRequestAndUpdateState = function () {
  692. patchFetchInfo({ isValidating: false });
  693. // We can only set state if it's safe (still mounted with the same key).
  694. if (isCurrentKeyMounted()) {
  695. setState(newState);
  696. }
  697. };
  698. // Start fetching. Change the `isValidating` state, update the cache.
  699. patchFetchInfo({
  700. isValidating: true
  701. });
  702. setState({ isValidating: true });
  703. _b.label = 1;
  704. case 1:
  705. _b.trys.push([1, 3, , 4]);
  706. if (shouldStartNewRequest) {
  707. // Tell all other hooks to change the `isValidating` state.
  708. broadcastState(cache, key, stateRef.current.data, stateRef.current.error, true);
  709. // If no cache being rendered currently (it shows a blank page),
  710. // we trigger the loading slow event.
  711. if (config.loadingTimeout && !cache.get(key)) {
  712. setTimeout(function () {
  713. if (loading && isCurrentKeyMounted()) {
  714. getConfig().onLoadingSlow(key, config);
  715. }
  716. }, config.loadingTimeout);
  717. }
  718. // Start the request and save the timestamp.
  719. FETCH[key] = [currentFetcher.apply(void 0, fnArgs), getTimestamp()];
  720. }
  721. _a = FETCH[key], newData = _a[0], startAt = _a[1];
  722. return [4 /*yield*/, newData];
  723. case 2:
  724. newData = _b.sent();
  725. if (shouldStartNewRequest) {
  726. // If the request isn't interrupted, clean it up after the
  727. // deduplication interval.
  728. setTimeout(cleanupState, config.dedupingInterval);
  729. }
  730. // If there're other ongoing request(s), started after the current one,
  731. // we need to ignore the current one to avoid possible race conditions:
  732. // req1------------------>res1 (current one)
  733. // req2---------------->res2
  734. // the request that fired later will always be kept.
  735. // The timestamp maybe be `undefined` or a number
  736. if (!FETCH[key] || FETCH[key][1] !== startAt) {
  737. if (shouldStartNewRequest) {
  738. if (isCurrentKeyMounted()) {
  739. getConfig().onDiscarded(key);
  740. }
  741. }
  742. return [2 /*return*/, false];
  743. }
  744. // Clear error.
  745. patchFetchInfo({
  746. error: UNDEFINED
  747. });
  748. newState.error = UNDEFINED;
  749. mutationInfo = MUTATION[key];
  750. if (!isUndefined(mutationInfo) &&
  751. // case 1
  752. (startAt <= mutationInfo[0] ||
  753. // case 2
  754. startAt <= mutationInfo[1] ||
  755. // case 3
  756. mutationInfo[1] === 0)) {
  757. finishRequestAndUpdateState();
  758. if (shouldStartNewRequest) {
  759. if (isCurrentKeyMounted()) {
  760. getConfig().onDiscarded(key);
  761. }
  762. }
  763. return [2 /*return*/, false];
  764. }
  765. // Deep compare with latest state to avoid extra re-renders.
  766. // For local state, compare and assign.
  767. if (!compare(stateRef.current.data, newData)) {
  768. newState.data = newData;
  769. }
  770. else {
  771. // data and newData are deeply equal
  772. // it should be safe to broadcast the stale data
  773. newState.data = stateRef.current.data;
  774. // At the end of this function, `brocastState` invokes the `onStateUpdate` function,
  775. // which takes care of avoiding the re-render
  776. }
  777. // For global state, it's possible that the key has changed.
  778. // https://github.com/vercel/swr/pull/1058
  779. if (!compare(cache.get(key), newData)) {
  780. cache.set(key, newData);
  781. }
  782. // Trigger the successful callback if it's the original request.
  783. if (shouldStartNewRequest) {
  784. if (isCurrentKeyMounted()) {
  785. getConfig().onSuccess(newData, key, config);
  786. }
  787. }
  788. return [3 /*break*/, 4];
  789. case 3:
  790. err_1 = _b.sent();
  791. cleanupState();
  792. // Not paused, we continue handling the error. Otherwise discard it.
  793. if (!getConfig().isPaused()) {
  794. // Get a new error, don't use deep comparison for errors.
  795. patchFetchInfo({ error: err_1 });
  796. newState.error = err_1;
  797. // Error event and retry logic. Only for the actual request, not
  798. // deduped ones.
  799. if (shouldStartNewRequest && isCurrentKeyMounted()) {
  800. getConfig().onError(err_1, key, config);
  801. if ((typeof config.shouldRetryOnError === 'boolean' &&
  802. config.shouldRetryOnError) ||
  803. (isFunction(config.shouldRetryOnError) &&
  804. config.shouldRetryOnError(err_1))) {
  805. // When retrying, dedupe is always enabled
  806. if (isActive()) {
  807. // If it's active, stop. It will auto revalidate when refocusing
  808. // or reconnecting.
  809. getConfig().onErrorRetry(err_1, key, config, revalidate, {
  810. retryCount: (opts.retryCount || 0) + 1,
  811. dedupe: true
  812. });
  813. }
  814. }
  815. }
  816. }
  817. return [3 /*break*/, 4];
  818. case 4:
  819. // Mark loading as stopped.
  820. loading = false;
  821. // Update the current hook's state.
  822. finishRequestAndUpdateState();
  823. // Here is the source of the request, need to tell all other hooks to
  824. // update their states.
  825. if (isCurrentKeyMounted() && shouldStartNewRequest) {
  826. broadcastState(cache, key, newState.data, newState.error, false);
  827. }
  828. return [2 /*return*/, true];
  829. }
  830. });
  831. }); },
  832. // `setState` is immutable, and `eventsCallback`, `fnArgs`, `keyInfo`,
  833. // and `keyValidating` are depending on `key`, so we can exclude them from
  834. // the deps array.
  835. //
  836. // FIXME:
  837. // `fn` and `config` might be changed during the lifecycle,
  838. // but they might be changed every render like this.
  839. // `useSWR('key', () => fetch('/api/'), { suspense: true })`
  840. // So we omit the values from the deps array
  841. // even though it might cause unexpected behaviors.
  842. // eslint-disable-next-line react-hooks/exhaustive-deps
  843. [key]);
  844. // Similar to the global mutate, but bound to the current cache and key.
  845. // `cache` isn't allowed to change during the lifecycle.
  846. // eslint-disable-next-line react-hooks/exhaustive-deps
  847. var boundMutate = useCallback(
  848. // By using `bind` we don't need to modify the size of the rest arguments.
  849. internalMutate.bind(UNDEFINED, cache, function () { return keyRef.current; }),
  850. // eslint-disable-next-line react-hooks/exhaustive-deps
  851. []);
  852. // Always update fetcher and config refs.
  853. useIsomorphicLayoutEffect(function () {
  854. fetcherRef.current = fetcher;
  855. configRef.current = config;
  856. });
  857. // After mounted or key changed.
  858. useIsomorphicLayoutEffect(function () {
  859. if (!key)
  860. return;
  861. // Not the initial render.
  862. var keyChanged = initialMountedRef.current;
  863. var softRevalidate = revalidate.bind(UNDEFINED, WITH_DEDUPE);
  864. // Expose state updater to global event listeners. So we can update hook's
  865. // internal state from the outside.
  866. var onStateUpdate = function (updatedData, updatedError, updatedIsValidating) {
  867. setState(mergeObjects({
  868. error: updatedError,
  869. isValidating: updatedIsValidating
  870. },
  871. // Since `setState` only shallowly compares states, we do a deep
  872. // comparison here.
  873. compare(stateRef.current.data, updatedData)
  874. ? UNDEFINED
  875. : {
  876. data: updatedData
  877. }));
  878. };
  879. // Expose revalidators to global event listeners. So we can trigger
  880. // revalidation from the outside.
  881. var nextFocusRevalidatedAt = 0;
  882. var onRevalidate = function (type) {
  883. if (type == FOCUS_EVENT) {
  884. var now = Date.now();
  885. if (getConfig().revalidateOnFocus &&
  886. now > nextFocusRevalidatedAt &&
  887. isActive()) {
  888. nextFocusRevalidatedAt = now + getConfig().focusThrottleInterval;
  889. softRevalidate();
  890. }
  891. }
  892. else if (type == RECONNECT_EVENT) {
  893. if (getConfig().revalidateOnReconnect && isActive()) {
  894. softRevalidate();
  895. }
  896. }
  897. else if (type == MUTATE_EVENT) {
  898. return revalidate();
  899. }
  900. return;
  901. };
  902. var unsubUpdate = subscribeCallback(key, STATE_UPDATERS, onStateUpdate);
  903. var unsubEvents = subscribeCallback(key, EVENT_REVALIDATORS, onRevalidate);
  904. // Mark the component as mounted and update corresponding refs.
  905. unmountedRef.current = false;
  906. keyRef.current = key;
  907. initialMountedRef.current = true;
  908. // When `key` updates, reset the state to the initial value
  909. // and trigger a rerender if necessary.
  910. if (keyChanged) {
  911. setState({
  912. data: data,
  913. error: error,
  914. isValidating: isValidating
  915. });
  916. }
  917. // Trigger a revalidation.
  918. if (shouldRevalidateOnMount()) {
  919. if (isUndefined(data) || IS_SERVER) {
  920. // Revalidate immediately.
  921. softRevalidate();
  922. }
  923. else {
  924. // Delay the revalidate if we have data to return so we won't block
  925. // rendering.
  926. rAF(softRevalidate);
  927. }
  928. }
  929. return function () {
  930. // Mark it as unmounted.
  931. unmountedRef.current = true;
  932. unsubUpdate();
  933. unsubEvents();
  934. };
  935. }, [key, revalidate]);
  936. // Polling
  937. useIsomorphicLayoutEffect(function () {
  938. var timer;
  939. function next() {
  940. // Use the passed interval
  941. // ...or invoke the function with the updated data to get the interval
  942. var interval = isFunction(refreshInterval)
  943. ? refreshInterval(data)
  944. : refreshInterval;
  945. // We only start next interval if `refreshInterval` is not 0, and:
  946. // - `force` is true, which is the start of polling
  947. // - or `timer` is not 0, which means the effect wasn't canceled
  948. if (interval && timer !== -1) {
  949. timer = setTimeout(execute, interval);
  950. }
  951. }
  952. function execute() {
  953. // Check if it's OK to execute:
  954. // Only revalidate when the page is visible, online and not errored.
  955. if (!stateRef.current.error &&
  956. (refreshWhenHidden || getConfig().isVisible()) &&
  957. (refreshWhenOffline || getConfig().isOnline())) {
  958. revalidate(WITH_DEDUPE).then(next);
  959. }
  960. else {
  961. // Schedule next interval to check again.
  962. next();
  963. }
  964. }
  965. next();
  966. return function () {
  967. if (timer) {
  968. clearTimeout(timer);
  969. timer = -1;
  970. }
  971. };
  972. }, [refreshInterval, refreshWhenHidden, refreshWhenOffline, revalidate]);
  973. // Display debug info in React DevTools.
  974. useDebugValue(data);
  975. // In Suspense mode, we can't return the empty `data` state.
  976. // If there is `error`, the `error` needs to be thrown to the error boundary.
  977. // If there is no `error`, the `revalidation` promise needs to be thrown to
  978. // the suspense boundary.
  979. if (suspense && isUndefined(data) && key) {
  980. // Always update fetcher and config refs even with the Suspense mode.
  981. fetcherRef.current = fetcher;
  982. configRef.current = config;
  983. throw isUndefined(error) ? revalidate(WITH_DEDUPE) : error;
  984. }
  985. return {
  986. mutate: boundMutate,
  987. get data() {
  988. stateDependencies.data = true;
  989. return data;
  990. },
  991. get error() {
  992. stateDependencies.error = true;
  993. return error;
  994. },
  995. get isValidating() {
  996. stateDependencies.isValidating = true;
  997. return isValidating;
  998. }
  999. };
  1000. };
  1001. var SWRConfig = OBJECT.defineProperty(SWRConfig$1, 'default', {
  1002. value: defaultConfig
  1003. });
  1004. var unstable_serialize = function (key) { return serialize(key)[0]; };
  1005. var useSWR = withArgs(useSWRHandler);
  1006. // useSWR
  1007. export { SWRConfig, useSWR as default, mutate, unstable_serialize, useSWRConfig };