キャッシュは管理が難しい。認識漏れを起こしやすく意図しないバグ混入するので注意して実装する。
デフォルトでrevalidateを抑制しているuseSWRImmutableの方を採用する。
mutationの方法にも様々あるけど、mutationの際に直接ローカルキャッシュを変更しrevalidateを起こさせない方法を採用したい。参考リンクでいう"Mutate Based on Current Data"を使う。
"Bounce Mutate"を使わないためmutate関数はswr
から直接持ってくるか、useSWRConfig
の返り値から取り出す。
import { mutate } from "swr"
or const { mutate } = useSWRConfig()
。
mutate(key, data?, shouldRevalidate?)
関数の第一引数は変更するローカルキャッシュのキー、第二引数はローカルキャッシュに反映させるデータorデータを返す関数(Promiseでも可)、
第三引数はrevalidateの可否。
// src/usecases/book.ts
export const useAddBook = async (book: Book) => {
await addBook(book);
await mutate(
generateCacheKey(),
() => (prev?: Book[]) => {
if (!prev) return;
return [...prev, book];
},
false
);
};
複数のキャッシュを更新したい場合は続けてmutate関数を記述する。正規表現でキーを指定して一括でrevalidateする方法もあるようだけど、そろそろしんどくなってくる。
export const useUpdateBook = async (id: string, book: Book) => {
await updateBook(id, book);
await mutate(
generateCacheKey(),
() => (prev?: Book[]) => {
if (!prev) return;
return prev.map((prevBook) => (prevBook.id === id ? book : prevBook));
},
false
);
await mutate(generateCacheKey(id), book, false);
};
カリー関数でmodelごとのキャッシュ生成関数を作成する君。
// src/lib/swr.ts
export const getCacheKeyGenerator =
(model: string) =>
(...keySegments: string[]) =>
`${model}${keySegments.length > 0 ? `/${keySegments.join("/")}` : ""}`;
Firestoreへの依存を持ってしまうが、○○Refecrenceからidやpathが取れるのでそれをキーにしてもいいかもしれない。