📦

SWRでリスト系のAPIの結果から個別のキャッシュも作る

2023/01/16に公開

背景

以下のようなAPIがあるとして、

  • GET /api/user/:user_id 特定のユーザを返す
  • GET /api/user ユーザの一覧をページングして返す (offset, limit)

クライアントアプリでリストAPIのレスポンスをユーザ単体のキャッシュとしても機能させたい。

これを SWRを使いながらやろうという話です。

あ。今回は suspense してないです。

キーワード

実際のコード

リストAPIの結果から単体のキャッシュを作る

mutate のラッパーを作る

まずは剥き出しの mutate をラップしてuseSWRのキーを隠蔽します。
["/api/user/:userId", user.id] の部分が useSWR の第一引数と一貫する必要があるからです。

const useMutateUser = () => {
  const { mutate } = useSWRConfig();

  return React.useCallback(
    (user: User) => {
      // この第一引数を外に出したくない
      mutate(["/api/user/:userId", user.id], user, { revalidate: false });
    },
    [mutate]
  );
}

const useUser = (userId: User['id']) => {
  return useSWR(
    ["/api/user/:userId", userId],
    ...
  );
}

副作用として個別キャッシュを作る

あとは副作用としてページの結果を返す前にキャッシュを作るだけです。

// キャッシュ用のインターフェースを持ってきて
const mutateUser = useMutateUser();

useSWRInfinite(
  ...,
  async (...) => {
    // response = {list: User[]}
    const response = await fetchUsers(...);
    // 使うだけ
    response.list.forEach(mutateUser);
    return response;
  },
);

まとめ

useSWRInfinite から useSWR のキャッシュを mutate をつかって作る。」という話でした。

テストのための msw のハンドラーの実装についても触れようかと思ってたんですが長くなるのでやめました。
別記事にしようかと思っていますが、資料に実装済みのものがあります。

Discussion