9
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

SWRでログアウト時やユーザー切り替え時に「キャッシュを全部消したい」場面、ありますよね。今回は、そこで盛大にハマった話です。

最初にやったこと

まず思いついたのがこれ。

const { cache } = useSWRConfig();

// これはNG
for (const key of cache.keys()) {
  cache.delete(key);
}

cacheがMapっぽいしkeys()delete()もあるし、「これで全消しできるでしょ」と思いました。

ここから沼が始まります。

実際に起きた謎現象

isLoadingが永遠にtrueなのに通信が飛ばない

これが一番怖いやつ。

const { data, isLoading } = useSWR('/api/hoge', fetcher);
  • isLoading === true
  • data === undefined
  • Networkタブ:何も飛んでない
  • エラーも出ない

つまり、「今ロード中です(嘘)」 という状態。

UIは永遠にスピナーが回り続けます。fetcherもAPIも問題ないのに、SWRが沈黙するという最悪の状態でした。

mutate()で明示的に呼ばないとデータが取得できない

mutate('/api/user');

このように手動でmutateしたものだけは取得できる。

しかし、普通のuseSWRは一切データを取りに行かない。

// これが動かない
useSWR('/api/hoge', fetcher);

なぜこうなったのか

cache.delete(key)はMapライクな操作ですが、SWRの内部状態($req$len$infなど)は別管理されています。

// cache.delete()で消えるのはキャッシュの「値」だけ
// SWR内部の状態管理は壊れたまま残る
// → 状態の不整合が発生

結果としてSWRは「このkeyはもう処理済み」と誤認し、fetchを投げないままisLoadingtrueで固まる半壊状態に陥りました。

正解:mutate()で全てundefinedにする

正解はこれでした。

const { mutate } = useSWRConfig();

// 全てのキャッシュを正しく削除する
mutate(
  (key) => true,           // すべてのキーにマッチ
  undefined,               // キャッシュの値をクリア
  { revalidate: false }    // 消した直後に再fetchしない
);

これにより、キャッシュの更新・状態遷移・useSWRへの通知がSWRの正規ルートで処理されます。

ちなみにrevalidate: trueにすると、キャッシュクリア直後に全キーで再fetchが走ります。ログアウト時など「消すだけでいい」場面ではfalseが適切です。

オチ:普通にReferenceに書いてあった

散々ハマってから公式ドキュメントを読み直したところ、

"In most cases, you shouldn't directly write to the cache, which might cause undefined behaviors of SWR."

しれっと書いてありました。

まとめ

  • cache.delete()で全消しすると状態が壊れる
  • isLoadingtrueのまま通信が飛ばない半壊状態になる
  • 正解は mutate((key) => true, undefined, { revalidate: false })
  • 答えは公式Referenceに書いてあった

ドキュメントは先に読みましょう。

参考

9
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?