useMemoize

useMemoize

引数に依存する関数の結果をキャッシュし、リアクティブに保ちます。非同期関数にも使用でき、同じデータを同時にフェッチすることを避けるために既存のプロミスを再利用します。

::: tip 結果は自動的にクリアされません。結果が不要になった場合は clear() を呼び出すか、独自のキャッシュメカニズムを使用してメモリリークを避けてください。 :::

使用法

import { useMemoize } from '@vueuse/core'

const getUser = useMemoize(
  async (userId: number): Promise<UserData> =>
    axios.get(`users/${userId}`).then(({ data }) => data),
)

const user1 = await getUser(1) // users/1 をリクエスト
const user2 = await getUser(2) // users/2 をリクエスト
// ...
const user1 = await getUser(1) // キャッシュから取得

// ...
const user1 = await getUser.load(1) // users/1 をリクエスト

// ...
getUser.delete(1) // ユーザー1のキャッシュを削除
getUser.clear() // 全キャッシュをクリア

computed または computedAsync と組み合わせてリアクティビティを実現します:

import { computedAsync, useMemoize } from '@vueuse/core'

const getUser = useMemoize(
  async (userId: number): Promise<UserData> =>
    axios.get(`users/${userId}`).then(({ data }) => data),
)
// ---cut---
const user1 = computedAsync(() => getUser(1))
// ...
await getUser.load(1) // user1 も更新されます

キャッシュキーの解決

キャッシュのキーは関数に与えられた引数によって決定され、デフォルトでは JSON.stringify でシリアライズされます。これにより、等しいオブジェクトが同じキャッシュキーを受け取ることができます。キーをカスタマイズしたい場合は getKey を渡すことができます。

import { useMemoize } from '@vueuse/core'
// ---cut---
const getUser = useMemoize(
  async (userId: number, headers: AxiosRequestHeaders): Promise<UserData> =>
    axios.get(`users/${userId}`, { headers }).then(({ data }) => data),
  {
    // userId のみを使用してキャッシュを取得/設定し、headers を無視
    getKey: (userId, headers) => userId,
  },
)

キャッシュメカニズムのカスタマイズ

デフォルトでは、結果は Map 内にキャッシュされます。以下の構造を持つ cache をオプションとして渡すことで、独自のメカニズムを実装できます:

export interface MemoizeCache<Key, Value> {
  /**
   * キーに対する値を取得
   */
  get: (key: Key) => Value | undefined
  /**
   * キーに対する値を設定
   */
  set: (key: Key, value: Value) => void
  /**
   * キーが存在するかのフラグを返す
   */
  has: (key: Key) => boolean
  /**
   * キーに対する値を削除
   */
  delete: (key: Key) => void
  /**
   * キャッシュをクリア
   */
  clear: () => void
}