useSWRInfiniteを使ったらmutateされなくなった話
TL;DR😍
import useSWRInfinite from "swr/infinite";
// 中略
const fetcher = useCallback(
(url: string) => fetch(url).then((res) => res.json()),
[]
);
const {
data: timelines,
size,
setSize,
isValidating,
mutate, // こいつが今回の主役
} = useSWRInfinite(getKey, fetcher, {
revalidateFirstPage: false,
parallel: true,
});
const hogehoge = useCallback((content: string) => {
// なにかしらのPostやらでmutateしたい処理
mutate();
}, [])
コレだけでちゃんとmutateしてくれるみたいでした。
なぜこのようなことが起きたのか🤔
今までuseSWRを使用してデータを取得していたのですが、無限ローディングを実装したいと思いuseSWRInfiniteを使用するに至りました。
その中で、今まで行なっていたmutateではきちんと動作しないことを確認し、どのように実装すればいいのか正直わからないでいました。
公式ドキュメント(日本語訳済み)をみても、確かにmutateの記載はあるのですが、使用例がなく分かりづらい状況でした。
ここで詰まっている誰かの援助になれたら幸いです。
裏側を覗いてみよう👀
では、なぜuseSWRの方のmutateではうまくデータが取得できなかったのでしょうか。
技術的な背景🔧
useSWRとuseSWRInfiniteは、それぞれ異なるユースケースに対応するために設計されているみたいです。
useSWRは単一のデータソースを扱うのに対して、useSWRInfiniteはページネーションされたデータを扱います。この違いがmutateの挙動にも影響を与えます。
useSWRのmutateは単一のキャッシュエントリを更新するため、単一のデータソースに対しては問題なく動作します。しかし、useSWRInfiniteでは複数のページにまたがるデータを管理するため、mutateもそれに対応する必要があります。具体的には、useSWRInfiniteのmutateは全ページのキャッシュを一括で更新し、再検証をトリガーするように設計されています。賢いですねえ
このため、useSWRのmutateをそのままuseSWRInfiniteに適用すると、期待通りに動作しないことがあります。useSWRInfiniteのmutateを使用することで、全ページのデータを正しく更新し、再検証を行うことができます。
具体的な解決策🛠️
では、具体的にどのようにuseSWRInfiniteのmutateを使用すれば良いのでしょうか?以下にその方法を示します。
まず、useSWRInfiniteのmutateは引数を取らずに呼び出すことができます。これにより、全ページのデータが再検証されます。
const { data, mutate } = useSWRInfinite(getKey, fetcher);
// データの更新後に全ページを再検証
mutate();
特定のページのみを更新したい場合は、以下のように特定のページのデータを直接更新することも可能です。
const { data, mutate } = useSWRInfinite(getKey, fetcher);
// 特定のページのデータを更新
mutate((pages) => {
const updatedPages = [...pages];
updatedPages[0] = newData; // 例えば最初のページを更新
return updatedPages;
});
このように、useSWRInfiniteのmutateを適切に使用することで、無限ローディングのデータ管理がより効率的に行えるようになります。
目指せuseSWRマスター🙌
あとがき
フロントエンドはとっつきやすい分”沼”ですねえ
筆者
参考文献
Discussion