開発完了
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- 色分け表示ロジック