@gera2ld/async-memo
v1.0.0
Published
Cache asynchronous functions where they should be
Readme
@gera2ld/async-memo
Usage
Quick Start
import { asyncMemo } from '@gera2ld/async-memo';
const myApi = asyncMemo(myApiCall, {
resolver: (params) => [groupKey, cacheKey],
});
// Call from anywhere
async function someAction() {
const response = await myApi(params);
}
// Get the current value anytime
function getValueSync() {
return myApi.get(params);
}
// Get context to avoid passing args around
function otherPlace() {
const ctx = myApi.context(params);
ctx.get(); // sync get
ctx.reload(); // refresh data
ctx.isSettled(); // check loading state
}Each groupKey has its own cache. The cache is invalidated when the cacheKey changes.
Options
interface CacheOptions<T extends unknown[]> {
/** Convert args into cacheGroup and cacheKey.
* By default the function is only evaluated once. */
resolver: (...args: T) => string | [cacheGroup: string, cacheKey: string];
/** Whether stale value should be returned. Default: false */
mustRevalidate: boolean;
/** Time to live in ms, -1 for always. Default: -1 */
ttl: number;
}Use Cases
Load once globally
This is the default behavior.
const loadOnceGlobally = asyncMemo(api);
// or
const loadOnceGlobally = asyncMemo(api, {
resolver: () => '',
});Load on param change
const loadOnParamChange = asyncMemo(api, {
resolver: (params) => ['', JSON.stringify(params)],
});Cache data for multiple tabs
The data for each tab will be cached in a different group, with the parameters as its cache key.
const loadOnParamChange = asyncMemo(api, {
resolver: (params) => [params.tab, JSON.stringify(params)],
});Custom Cache Store
For frameworks like MobX or Vue, you can provide a custom cache store:
import { createAsyncMemo } from '@gera2ld/async-memo';
function createCache<T>() {
// ... your cache implementation
return {
get(cacheKey: string) { ... },
set(cacheKey: string, data?: T) { ... },
clear() { ... },
};
}
const asyncMemo = createAsyncMemo(createCache);import { observable } from 'mobx';
function createCache<T>() {
const target = observable<{ value: Record<string, T | undefined> }>(
{ value: {} },
{ value: observable.ref },
);
return {
get(cacheKey: string) {
return target.value[cacheKey];
},
set(cacheKey: string, data?: T) {
target.value = { ...target.value, [cacheKey]: data };
},
clear() {
target.value = {};
},
};
}import { ref } from 'vue';
function createCache<T>() {
const target = ref<Record<string, T | undefined>>({});
return {
get(cacheKey: string) {
return target.value[cacheKey];
},
set(cacheKey: string, data?: T) {
target.value = { ...target.value, [cacheKey]: data };
},
clear() {
target.value = {};
},
};
}