useCachePlugin.ts 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. import { onUnmounted, ref, watchEffect } from 'vue';
  2. import type { UseRequestPlugin } from '../types';
  3. import type { CachedData } from '../utils/cache';
  4. import { getCache, setCache } from '../utils/cache';
  5. import { getCachePromise, setCachePromise } from '../utils/cachePromise';
  6. import { subscribe, trigger } from '../utils/cacheSubscribe';
  7. const useCachePlugin: UseRequestPlugin<any, any[]> = (
  8. fetchInstance,
  9. {
  10. cacheKey,
  11. cacheTime = 5 * 60 * 1000,
  12. staleTime = 0,
  13. setCache: customSetCache,
  14. getCache: customGetCache,
  15. },
  16. ) => {
  17. const unSubscribeRef = ref<() => void>();
  18. const currentPromiseRef = ref<Promise<any>>();
  19. const _setCache = (key: string, cachedData: CachedData) => {
  20. customSetCache ? customSetCache(cachedData) : setCache(key, cacheTime, cachedData);
  21. trigger(key, cachedData.data);
  22. };
  23. const _getCache = (key: string, params: any[] = []) => {
  24. return customGetCache ? customGetCache(params) : getCache(key);
  25. };
  26. watchEffect(() => {
  27. if (!cacheKey) return;
  28. // get data from cache when init
  29. const cacheData = _getCache(cacheKey);
  30. if (cacheData && Object.hasOwnProperty.call(cacheData, 'data')) {
  31. fetchInstance.state.data = cacheData.data;
  32. fetchInstance.state.params = cacheData.params;
  33. if (staleTime === -1 || new Date().getTime() - cacheData.time <= staleTime) {
  34. fetchInstance.state.loading = false;
  35. }
  36. }
  37. // subscribe same cachekey update, trigger update
  38. unSubscribeRef.value = subscribe(cacheKey, (data) => {
  39. fetchInstance.setState({ data });
  40. });
  41. });
  42. onUnmounted(() => {
  43. unSubscribeRef.value?.();
  44. });
  45. if (!cacheKey) {
  46. return {};
  47. }
  48. return {
  49. onBefore: (params) => {
  50. const cacheData = _getCache(cacheKey, params);
  51. if (!cacheData || !Object.hasOwnProperty.call(cacheData, 'data')) {
  52. return {};
  53. }
  54. // If the data is fresh, stop request
  55. if (staleTime === -1 || new Date().getTime() - cacheData.time <= staleTime) {
  56. return {
  57. loading: false,
  58. data: cacheData?.data,
  59. error: undefined,
  60. returnNow: true,
  61. };
  62. } else {
  63. // If the data is stale, return data, and request continue
  64. return { data: cacheData?.data, error: undefined };
  65. }
  66. },
  67. onRequest: (service, args) => {
  68. let servicePromise = getCachePromise(cacheKey);
  69. // If has servicePromise, and is not trigger by self, then use it
  70. if (servicePromise && servicePromise !== currentPromiseRef.value) {
  71. return { servicePromise };
  72. }
  73. servicePromise = service(...args);
  74. currentPromiseRef.value = servicePromise;
  75. setCachePromise(cacheKey, servicePromise);
  76. return { servicePromise };
  77. },
  78. onSuccess: (data, params) => {
  79. if (cacheKey) {
  80. // cancel subscribe, avoid trgger self
  81. unSubscribeRef.value?.();
  82. _setCache(cacheKey, { data, params, time: new Date().getTime() });
  83. // resubscribe
  84. unSubscribeRef.value = subscribe(cacheKey, (d) => {
  85. fetchInstance.setState({ data: d });
  86. });
  87. }
  88. },
  89. onMutate: (data) => {
  90. if (cacheKey) {
  91. // cancel subscribe, avoid trigger self
  92. unSubscribeRef.value?.();
  93. _setCache(cacheKey, {
  94. data,
  95. params: fetchInstance.state.params,
  96. time: new Date().getTime(),
  97. });
  98. // resubscribe
  99. unSubscribeRef.value = subscribe(cacheKey, (d) => {
  100. fetchInstance.setState({ data: d });
  101. });
  102. }
  103. },
  104. };
  105. };
  106. export default useCachePlugin;