import { useEffect, useRef, useState } from "react"; import { getApiCache, getGlobalStorage } from "./storage"; interface UseSWCOPtions { onError?: (e: unknown) => void; onLoad?: (data: T) => void; cacheOnly?: boolean; cacheTimeout?: number; } // 该hook用于在组件中通过key和异步action获取数据,并自动处理加载、错误和数据状态 export function useSWC(key: string, action: () => Promise, options?: UseSWCOPtions) { const optionsRef = useRef(options); optionsRef.current = options; const [data, setData] = useState(() => { try { const data = JSON.parse(getApiCache().getString(`$swc-${key}`) || "null") as T; if (!data) { return undefined; } let ttl = optionsRef.current?.cacheTimeout || MAX_CACHE_TIME; // @ts-ignore let cacheTime = data.$__cacheTime; if (Date.now() - cacheTime > ttl * 1000) { return undefined; } return data; // eslint-disable-next-line @typescript-eslint/no-unused-vars } catch (_) { return undefined; } }); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const actionRef = useRef(action); actionRef.current = action; const dataRef = useRef(data); dataRef.current = data; const keyRef = useRef(key); useEffect(() => { let isMounted = true; if (dataRef.current && optionsRef.current?.cacheOnly) { return; } setLoading(true); setError(null); const options = optionsRef.current; const key = keyRef.current; actionRef.current() .then((result) => { // @ts-ignore result.$__cacheTime = Date.now(); result && getApiCache().set(`$swc-${key}`, JSON.stringify(result)); if (isMounted) { options?.onLoad?.(result); setData(result); setLoading(false); } }) .catch((err) => { if (isMounted) { options?.onError?.(err); setError(err); setLoading(false); } }); return () => { isMounted = false; }; }, []); return { data, loading, error }; } export const MAX_CACHE_TIME = 99999999999999; let lastClearTime = parseInt(getGlobalStorage().getString("last_clear_time") || "0"); const clearTimeout = 86400 * 3 * 1000; // 开启一直 30 分钏的定时器,用于清理缓存 setInterval(() => { let now = Date.now(); if (now - lastClearTime < clearTimeout) { lastClearTime = now; const globalStorage = getGlobalStorage(); const caches = getApiCache(); caches.getAllKeys().forEach(key => { try { let {$__cacheTime} = JSON.parse(caches.getString(key) || `{"$__cacheTime": ${MAX_CACHE_TIME}}`); if (now - $__cacheTime > clearTimeout) { caches.remove(key); } // eslint-disable-next-line @typescript-eslint/no-unused-vars } catch (_e) { } }); globalStorage.set("last_clear_time", now+""); } }, 60 * 15 * 1000);