@piotr-cz/swr-idb-cache
TypeScript icon, indicating that this package has built-in type declarations

1.0.3 • Public • Published

IndexedDB Cache Provider for SWR

Synchronize SWR Cache with IndexedDB to get offline cache.

Please note that the cache provider initialization process is asynchronous and until it's resolved best practise is to render fallback component.

How does it work?

Library reads current state of cache stored in IndexedDB into memory using idb during it's initialization. Then it resolves into Cache Provider which should be passed to SWR.

Read SWR Docs > Cache if your are interested in more information about implementation details.

Installation

Using npm:

npm install --save @piotr-cz/swr-idb-cache

or Yarn:

yarn add @piotr-cz/swr-idb-cache

Requirements

  • SWR ^2.0.0
    Note: For SWR 1.x use the 1.0.0-rc.2 version of this package
  • Works with React ^16.11 and Preact

Setup

Initialize library and when it's ready, pass it in configuration under provider key to SWR.

To wait until provider is resolved, use bundled useCacheProvider hook:

// App.jsx
import { SWRConfig } from 'swr'
import { useCacheProvider } from '@piotr-cz/swr-idb-cache'

function App() {
  // Initialize
  const cacheProvider = useCacheProvider({
    dbName: 'my-app',
    storeName: 'swr-cache',
  })

  // Cache Provider is being initialized - render fallback component in the meantime
  if (!cacheProvider) {
    return <div>Initializing cache…</div>
  }

  return (
    <SWRConfig value={{
      provider: cacheProvider,
    }}>
      <Dashboard />
    </SWRConfig>
  )
}

…or library like react-use-promise:

import createCacheProvider from '@piotr-cz/swr-idb-cache'
import usePromise from 'react-use-promise'

function App() {
  // Initialize
  const [ cacheProvider ] = usePromise(() => createCacheProvider({
    dbName: 'my-app',
    storeName: 'swr-cache',
  }), [])

  // …
}

Configuration

  • dbName: IndexedDB Database name
  • storeName: IndexedDB Store name
  • storageHandler (optional): Custom Storage handler, see IStorageHandler interface
  • version (optional): Schema version, defaults to 1
  • onError (optional): Database error handler, defaults to noop function

Note: When using useCacheProvider, changing options doesn't create new cache provider.

Known issues

InvalidStateError

InvalidStateError
Failed to execute 'transaction' on 'IDBDatabase': The database connection is closing.

See idb Issue #229

Recipes

Delete cache entry

import useSWR, { useSWRConfig } from 'swr'

export default function Item() {
  const { data, error } = useSWR('/api/data')
  const { cache } = useSWRConfig()

  const handleRemove = () => {
    // Remove from state
    // …

    // Remove from cache with key used in useSWR hook
    cache.delete('/api/data')
  }

  return (
    <main>
      {/** Show item */}
      {data &&
        <h1>{data.label}</h1>
      }

      {/** Remove item */}
      <button onClick={handleRemove}>
        Remove
      </button>
    </main>
  )
}

Implement Garbage Collector

Define custom storage handler that extends timestamp storage

// custom-storage-handler.js
import { timestampStorageHandler } from '@piotr-cz/swr-idb-cache'

// Define max age of 7 days
const maxAge = 7 * 24 * 60 * 60 * 1e3

const gcStorageHandler = {
  ...timestampStorageHandler,
  // Revive each entry only when it's timestamp is newer than expiration
  revive: (key, storeObject) => 
    storeObject.ts > Date.now() - maxAge
      // Unwrapped value
      ? timestampStorageHandler.revive(key, storeObject)
      // Undefined to indicate item is stale
      : undefined,
}

export default gcStorageHandler

Pass it to configuration

 // App.jsx
 import { SWRConfig } from 'swr'
 import { useCacheProvider } from '@piotr-cz/swr-idb-cache'

+import customStorageHandler from './custom-storage-handler.js'
+
 function App() {
   // Initialize
   const cacheProvider = useCacheProvider({
     dbName: 'my-app',
     storeName: 'swr-cache',
+    storageHandler: customStorageHandler,
   })

   // …

Ignore API endpoints from cache persistence

Define custom storage handler that extends timestamp storage

// custom-storage-handler.js
import { timestampStorageHandler } from '@piotr-cz/swr-idb-cache'

const blacklistStorageHandler = {
  ...timestampStorageHandler,
  // Ignore entries fetched from API endpoints starting with /api/device
  replace: (key, value) =>
    !key.startsWith('/api/device/')
      // Wrapped value
      ? timestampStorageHandler.replace(key, value)
      // Undefined to ignore storing value
      : undefined,
}

export default blacklistStorageHandler

Pass it in configuration as in the recipe above

Readme

Keywords

Package Sidebar

Install

npm i @piotr-cz/swr-idb-cache

Weekly Downloads

443

Version

1.0.3

License

MIT

Unpacked Size

46 kB

Total Files

7

Last publish

Collaborators

  • piotr-cz