コンテンツへスキップ
ドキュメント
上級編
キャッシュ

キャッシュ

💡

この機能を使用するには、最新バージョン(≥ 1.0.0)にアップグレードしてください。

⚠️

ほとんどの場合、キャッシュに直接書き込むべきではありません。SWRの動作が予期せぬものになる可能性があります。キーを手動で変更する必要がある場合は、SWR APIを使用することを検討してください。
こちらも参照してください:ミューテーションテストケース間のキャッシュのリセット

デフォルトでは、SWRはグローバルキャッシュを使用して、すべてのコンポーネント間でデータを保存および共有します。ただし、SWRConfigproviderオプションを使用して、この動作をカスタマイズすることもできます。

キャッシュプロバイダーは、よりカスタマイズされたストレージでSWRを有効にすることを目的としています。

キャッシュプロバイダー

キャッシュプロバイダーは、次のTypeScript定義に一致するMapのようなオブジェクトです(swrからインポートできます)。

interface Cache<Data> {
  get(key: string): Data | undefined
  set(key: string, value: Data): void
  delete(key: string): void
  keys(): IterableIterator<string>
}

たとえば、JavaScriptのMap(新しいタブで開きます)インスタンスは、SWRのキャッシュプロバイダーとして直接使用できます。

キャッシュプロバイダーの作成

SWRConfigproviderオプションは、キャッシュプロバイダーを返す関数を取得します。そのプロバイダーは、そのSWRConfig境界内のすべてのSWRフックによって使用されます。例:

import useSWR, { SWRConfig } from 'swr'
 
function App() {
  return (
    <SWRConfig value={{ provider: () => new Map() }}>
      <Page/>
    </SWRConfig>
  )
}

<Page/>内のすべてのSWRフックはそのMapインスタンスから読み書きします。特定のユースケースに合わせて、他のキャッシュプロバイダー実装を使用することもできます。

💡

上記の例では、<App/>コンポーネントが再マウントされると、プロバイダーも再作成されます。キャッシュプロバイダーは、コンポーネントツリーの上位、またはレンダリングの外側に配置する必要があります。

ネストされている場合、SWRフックは上位レベルのキャッシュプロバイダーを使用します。上位レベルのキャッシュプロバイダーがない場合は、空のMapであるデフォルトのキャッシュプロバイダーにフォールバックします。

⚠️

キャッシュプロバイダーが使用されている場合、グローバルなmutateは、その<SWRConfig>境界内のSWRフックには**機能しません**。これを代わりに使用してください。

現在のキャッシュプロバイダーへのアクセス

Reactコンポーネント内では、useSWRConfigフックを使用して、mutateを含む現在のキャッシュプロバイダーと他の設定にアクセスする必要があります。

import { useSWRConfig } from 'swr'
 
function Avatar() {
  const { cache, mutate, ...extraConfig } = useSWRConfig()
  // ...
}

<SWRConfig>の下にない場合は、デフォルトの設定が返されます。

実験的:キャッシュプロバイダーの拡張

🧪

これは実験的な機能であり、将来のアップグレードで動作が変更される可能性があります。

複数の<SWRConfig>コンポーネントがネストされている場合、キャッシュプロバイダーを拡張できます。

provider関数の最初の引数は、上位レベルの<SWRConfig>のキャッシュプロバイダー(または親<SWRConfig>がない場合はデフォルトのキャッシュ)です。これを使用して、キャッシュプロバイダーを拡張できます。

<SWRConfig value={{ provider: (cache) => newCache }}>
  ...
</SWRConfig>

サンプル

LocalStorageベースの永続的キャッシュ

localStorageにキャッシュを同期したい場合があります。実装例を以下に示します。

function localStorageProvider() {
  // When initializing, we restore the data from `localStorage` into a map.
  const map = new Map(JSON.parse(localStorage.getItem('app-cache') || '[]'))
 
  // Before unloading the app, we write back all the data into `localStorage`.
  window.addEventListener('beforeunload', () => {
    const appCache = JSON.stringify(Array.from(map.entries()))
    localStorage.setItem('app-cache', appCache)
  })
 
  // We still use the map for write & read for performance.
  return map
}

次に、プロバイダーとして使用します。

<SWRConfig value={{ provider: localStorageProvider }}>
  <App/>
</SWRConfig>
💡

改善策として、メモリキャッシュをバッファとして使用し、定期的にlocalStorageに書き込むこともできます。IndexedDBまたはWebSQLを使用して、同様の階層型キャッシュを実装することもできます。

テストケース間のキャッシュのリセット

アプリケーションのテスト時に、テストケース間でSWRキャッシュをリセットしたい場合があります。空のキャッシュプロバイダーでアプリケーションをラップするだけで済みます。Jestを使った例を以下に示します。

describe('test suite', async () => {
  it('test case', async () => {
    render(
      <SWRConfig value={{ provider: () => new Map() }}>
        <App/>
      </SWRConfig>
    )
  })
})

キャッシュデータの変更

🚨

キャッシュに直接書き込むべきではありません。未定義の動作を引き起こす可能性があります。

mutate を使用してキャッシュを変更できます。例えば、以下の様にすべてのキャッシュデータをクリアできます。

const { mutate } = useSWRConfig()
 
mutate(
  key => true, // which cache keys are updated
  undefined, // update cache data to `undefined`
  { revalidate: false } // do not revalidate
)

詳細はこちらをご覧ください。