@piotr-cz/swr-idb-cache
code:tsx
// @ts-expect-error 型定義が export されていない
import { simpleStorageHandler, timestampStorageHandler, useCacheProvider } from '@piotr-cz/swr-idb-cache'
import { captureException } from '@sentry/react'
import { secondsToMilliseconds } from 'date-fns'
import React from 'react'
import { SWRConfig } from 'swr'
export const DoNotCache = '***DO_NOT_CACHE***' as const
export const ShortCache = '***SHORT_CACHE***' as const
const shortCacheTimeToLive = secondsToMilliseconds(30)
type StorageHandler = typeof timestampStorageHandler
type StoreObject = { value: unknown; ts: number }
function gcStorageHandler(maxAge: number): StorageHandler {
const revive: StorageHandler'revive' = (key: string, storeObject: StoreObject): unknown => { if (key.includes(DoNotCache)) {
// キャッシュ無効
return undefined
}
const ttl = key.includes(ShortCache) ? shortCacheTimeToLive : maxAge
if (storeObject.ts + ttl < Date.now()) {
// 有効期限切れ
return undefined
}
return timestampStorageHandler.revive(key, storeObject)
}
const replace: StorageHandler'replace' = (key: string, value: unknown): StoreObject | undefined => { if (key.includes(DoNotCache)) {
// キャッシュ無効
return undefined
}
return timestampStorageHandler.replace(key, value)
}
return {
...timestampStorageHandler,
revive,
replace,
}
}
// eslint-disable-next-line @typescript-eslint/naming-convention
export type SWRConfigWithCacheProps = {
storeName: string
maxAge: number
children: React.JSX.Element
renderFallback(): React.JSX.Element
}
// eslint-disable-next-line @typescript-eslint/naming-convention
export function SWRConfigWithCache({
storeName,
maxAge,
children,
renderFallback,
}: SWRConfigWithCacheProps): React.JSX.Element {
const provider = useCacheProvider({
dbName: 'annict-tracker',
storeName,
storageHandler: gcStorageHandler(maxAge),
version: 1,
onError: (reason: unknown) => {
captureException(reason)
},
})
if (!provider) {
return renderFallback()
}
return (
<SWRConfig
value={{
provider,
}}
{children}
</SWRConfig>
)
}