suspensive
suspensive copied to clipboard
[Feature]: createCache
Package Scope
@suspensive/cache
Description
add createCache
Possible Solution
No response
etc.
No response
const queryCache = createCache({
invalidateInterval: 2000,
})
queryCache.options()
queryCache.options()
const textQueryCache = () => queryCache.options({ cacheKey: [111,], cacheFn: () => Promise.resolve({ text: 5 }) })
return (
<queryCache.Provider>
<Cache {...textQueryCache()}>
{(cached) => cached.data}
</Cache>
</queryCache.Provider>
)
const Example = () => {
const queryCache = queryCache.use()
const { data: text } = queryCache.use(textQueryCache())
queryCache.invalidate()
queryCache.reset()
}
const unreachableUnique = symbol()
const createCache = ({ defaultOptions, options }) => {
const cacheUnique = symbol()
const context = createContext(defaultOptions)
return {
[unreachableUnique]: { cacheUnique, context }, // To make userCache["user" | "users"], not userCache.options["user" | "users"]
...combine(cacheUnique, unreachableUnique).with(options),
}
}
const Cache = Object.assign(({ children, ...options }) => children(useCache(options)), {
Provider: ({ cache }) => cache[unreachableUnique].context.Provider
})
const useCache = (options) => {
const cacheControl = useCacheControl(options[unreachableUnique].cache)
return useSyncExternalStore(
(sync) => cacheControl.subscribe(options, sync),
() => cacheControl.read(options),
() => cacheControl.read(options)
)
}
const queryCache = createCache({
user: {
fn: (userId: number) => api.user(userId),
invalidateInterval: 3000,
},
users: {
fn: () => api.users()
}
},
{
invalidateInterval: 2000,
})
return (
<Cache.Provider cache={queryCache}>
<Suspense>
<Cache {...queryCache.user(1)}>
{(cached) => cached.data}
</Cache>
</Suspense>
</Cache.Provider>
)
const Example = () => {
const queryCacheControl = useCacheControl(queryCache)
const cachedUser = useCache(queryCache.user(1))
queryCacheControl.invalidate(queryCache.user(1))
queryCacheControl.reset(queryCache.user(1))
}
const unreachableUnique = symbol()
const createCache = ({ defaultOptions, options }) => {
const cacheUnique = symbol()
const context = createContext(defaultOptions)
return {
[unreachableUnique]: { cacheUnique, context }, // To make userCache["user" | "users"], not userCache.options["user" | "users"]
...combine(cacheUnique, unreachableUnique).with(options),
}
}
const Cache = Object.assign(({ children, ...options }) => children(useCache(options)), {
Provider: ({ cache }) => cache[unreachableUnique].context.Provider
})
const useRead = (options) => {
const cache = useCache(options[unreachableUnique].cache)
return useSyncExternalStore(
(sync) => cache.subscribe(options, sync),
() => cache.read(options),
() => cache.read(options)
)
}
const queryCache = createCache({
user: {
fn: (userId: number) => api.user(userId),
invalidateInterval: 3000,
},
users: {
fn: () => api.users()
}
},
{
invalidateInterval: 2000,
})
return (
<Cache.Provider cache={queryCache}>
<Suspense>
<Cache {...queryCache.user(1)}>
{(cached) => cached.data}
</Cache>
</Suspense>
</Cache.Provider>
)
const Example = () => {
const queryCacheStore = useCacheStore(queryCache)
const cachedUser = useRead(queryCache.user(1))
queryCacheStore.invalidate(queryCache.user(1))
queryCacheStore.reset(queryCache.user(1))
}
There is a Cache under the CacheStore, and a Cacheable exists under the Cache. The following example code applies the hierarchy I mentioned.
@manudeli if there are any parts that are not properly synced, please share them with me!
People can be co-author:
| Candidate | Reasons | Count | Add this as commit message |
|---|---|---|---|
| @SEOKKAMONI | https://github.com/toss/suspensive/issues/1191#issuecomment-2295304331 https://github.com/toss/suspensive/issues/1191#issuecomment-2298662236 https://github.com/toss/suspensive/issues/1191 | 3 | Co-authored-by: SEOKKAMONI <[email protected]> |
| @manudeli | https://github.com/toss/suspensive/issues/1191#issuecomment-2267358179 https://github.com/toss/suspensive/issues/1191#issuecomment-2267411286 https://github.com/toss/suspensive/issues/1191#issuecomment-2295595481 | 3 | Co-authored-by: manudeli <[email protected]> |
I thought there is no name cachestore like below
const unreachableUnique = symbol()
const createCache = ({ defaultOptions, options }) => {
const cacheUnique = symbol()
const context = createContext(defaultOptions)
return {
[unreachableUnique]: { cacheUnique, context }, // To make userCache["user" | "users"], not userCache.options["user" | "users"]
...combine(cacheUnique, unreachableUnique).with(options),
}
}
const useRead = (options) => {
const cache = useCache(options[unreachableUnique].cache)
return useSyncExternalStore(
cache.subscribe,
() => cache.read(options),
() => cache.read(options)
)
}
const query = createCache({
user: {
fn: (userId: number) => api.user(userId),
invalidateInterval: 3000,
},
users: {
fn: () => api.users()
}
})
return (
<CacheProvider cache=[query]>
<Suspense>
<Read {...query.user(1)}>
{({ data: user }) => user.name}
</Read>
</Suspense>
</CacheProvider>
)
const Example = () => {
const queryCache = useCache(query)
const { data: user } = useRead(query.user(1))
user
queryCache.invalidate(query.user(1))
queryCache.reset(query.user(1))
}
Oh, I was mistaken. Controlling Cacheable through the Cache is indeed correct. Looking back at the interface I proposed, it was actually controlling Cacheable through CacheStore. Thank you for pointing out my mistake! So, is CacheStore not an interface that users actually interact with, but rather something that exists theoretically to represent a hierarchy?