话不多说,先上代码
import { useState, useMemo, useEffect, Dispatch, SetStateAction } from "react"
export type AsyncResult<T> = [T | undefined, boolean, any, Dispatch<SetStateAction<T | undefined>>]
export interface PromiseCacheOptions<K, V> {
data: Map<K, V>
promiseFn: (key: K) => Promise<V>
keyFn: (data: V, key: K) => K
}
export class PromiseCache<K, V> {
private cache: Map<K, Promise<V>> = new Map()
constructor(private options: PromiseCacheOptions<K, V>) {
}
async get(key: K): Promise<V> {
if (this.options.data.has(key)) {
return Promise.resolve(this.options.data.get(key)!!)
}
if (this.cache.has(key)) {
return this.cache.get(key)!!
}
const result = this.options.promiseFn(key).then((res: V) => {
this.options.data.set(key, res)
return res
})
this.cache.set(key, result)
return result
}
}
export function useAsync<T>(fn: () => Promise<T>, dependency?: React.DependencyList): AsyncResult<T> {
const [value, setValue] = useState<T | undefined>()
const [error, setError] = useState<any>(null)
const [loading, setLoading] = useState<boolean>(true)
const state = useMemo<{ count: number }>(() => { return { count: 0 } }, [])
const dep = dependency ?? [fn]
useEffect(() => {
setLoading(true);
setError(null);
let asyncFn = (count: number) => {
fn().then(r => {
if (count === state.count) {
setValue(r)
}
}).catch(e => {
if (count === state.count) {
setError(e)
}
}).finally(() => {
if (count === state.count) {
setLoading(false)
}
})
}
asyncFn(state.count + 1)
state.count++
}, dep)
return [value, loading, error, setValue]
}
import { PromiseCache, useAsync } from '@/lib/cache';
const Context = new PromiseCache<string, CacheType | undefined>({
data: new Map(),
promiseFn: (key: string) => {
const [project_id, type_id] = key.split('&')
return Promise().then(v => {
return v.data
})
},
keyFn: () => {
return ''
}
})
function method(props: Props) {
const [data, loading, err] = useAsync(async () => {
if (project_id && typeId!== undefined) {
const res = await Context.get(`id`)
return res.data
}
return undefined
}, [id])
return (
<></>
)
}
该方法通过map去存储promise请求,每次请求通过调用PromiseCache类的get方法先判断是否存在key来判断是否需要发送请求。
有小伙伴尝试的话,也可以试试改写成vue形式。