• #Nuxt
  • #Vue
  • #useAsyncData
  • #キャッシュ
  • #バグ修正
開発完了

Nuxt useAsyncDataのキャッシュ問題:クライアントナビゲーション時にデータが古い

結論

useAsyncData{ dedupe: 'defer' }オプションを追加することで解決。

// 修正前
const { data } = await useAsyncData('key', () => fetchData())

// 修正後
const { data } = await useAsyncData('key', () => fetchData(), { dedupe: 'defer' })

問題

BlogCalendarコンポーネントで、記事のtodoフィールドに応じた色分け表示が正しく動作しない現象が発生した。

症状

操作結果
別ページから /blog にナビゲートtodoの色が反映されない
/blog をリロードtodoの色が正しく表示される

期待動作

todo: "active"はオレンジ、todo: "done"はグレー、todo: "memo"はスカイブルーで表示されるべき。

原因

useAsyncDataのデフォルト動作では、同じキーのリクエストが以前に実行されていた場合、キャッシュされたデータを即座に返す。

const { data: contentArticles } = await useAsyncData('blog-content-articles', () =>
  queryCollection('pages')
    .select('title', 'description', 'path', 'tags', 'publishedAt', 'updatedAt', 'category', 'todo')
    .all()
)

クライアントサイドナビゲーション時、Nuxtは以前のSSRペイロードやキャッシュからデータを返す。このキャッシュに最新のtodoフィールドの値が含まれていなかったため、色が正しく表示されなかった。

解決策

dedupeオプションを'defer'に設定する。

const { data: contentArticles } = await useAsyncData('blog-content-articles', () =>
  queryCollection('pages')
    .select('title', 'description', 'path', 'tags', 'publishedAt', 'updatedAt', 'category', 'todo')
    .all(),
  { dedupe: 'defer' }
)

dedupeオプションの動作

動作
'cancel'(デフォルト)同じキーのリクエストが進行中なら、新しいリクエストをキャンセルしてキャッシュを返す
'defer'同じキーのリクエストが進行中なら、新しいリクエストは開始せず既存の完了を待つ

'defer'を指定することで、キャッシュを即座に返さず、データ取得の完了を待つようになる。

試したが失敗したアプローチ

getCachedData: () => null

{ getCachedData: () => null }

キャッシュを完全に無効化しようとしたが、ページが何も表示されなくなった。SSRとの相性が悪いと思われる。

まとめ

  • useAsyncDataはデフォルトでキャッシュを積極的に使用する
  • クライアントナビゲーション時に最新データが必要な場合はdedupe: 'defer'を検討
  • getCachedData: () => nullはSSR環境で問題を起こす可能性がある

関連ファイル

  • apps/web/app/pages/blog/index.vue - 修正対象
  • apps/web/app/components/BlogCalendar.vue - 色分け表示ロジック