🥺

useSWRInfiniteを使ったらmutateされなくなった話

2024/05/31に公開

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ではきちんと動作しないことを確認し、どのように実装すればいいのか正直わからないでいました。

https://swr.vercel.app/ja/docs/pagination#useswrinfinite

公式ドキュメント(日本語訳済み)をみても、確かに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マスター🙌

あとがき

フロントエンドはとっつきやすい分”沼”ですねえ

筆者

https://x.com/ryuji_vlog

参考文献

https://swr.vercel.app/ja/docs/pagination#useswrinfinite

Discussion