⛰️

Nuxt 3 useFetch ハマりポイント3つ

2022/10/18に公開
  1. [id].vue のページ、key を設定しないと違うIDのページで取得結果が更新されない
  2. useLazyFetch にしないとページ遷移がスムーズじゃなくなる
  3. initialCache がデフォで true

前提

10/18時点、"nuxt": "3.0.0-rc.11"
久しぶりに Nuxt を触った。Vue3, Nuxt3 をドキュメント見ながら使った。useFetch がゆーたら Nuxt3 の目玉機能的なやつやと思うけど割とハマった。

1. [id].vue のページ、key を設定しないと違うIDのページで取得結果が更新されない

「key 渡さん場合、useFetch 書いてるファイル名行番号を key にしますんで。」

If you do not provide a key, then a key that is unique to the file name and line number of the instance of useAsyncData will be generated for you.

(https://v3.nuxtjs.org/api/composables/use-async-data#params)

[userId].vue の31行目に useFetch 書いてたからどんなIDだろうと key 一緒やんけ。やってんな。key を渡して解決。

2. useLazyFetch にしないとページ遷移がスムーズじゃなくなる

遷移先のページで useFetch が発動すると取得が済むまで遷移してくれない。

By default, useFetch blocks navigation until its async handler is resolved.

(https://v3.nuxtjs.org/api/composables/use-lazy-fetch)

Vue の Suspense が関係しているんだろうか。
https://vuejs.org/guide/built-ins/suspense.html#async-dependencies'

useLazyFetch を使うとすぐ遷移してくれる。ただし最初は取得結果が null なのを考慮してコードを書く必要がある。

3. initialCache がデフォで true

false にしたら「常に最新の状態が反映される」から嬉しい気持ちになる。

useFetch も useAsyncData も、デフォルトでデータがキャッシュされ、同じkeyに対して一度リクエストしていたら、それ以降は再検証を行いません。

これはページ遷移などで別のコンポーネントがマウントされた場合も、共通のkeyであればAPIリクエストは行わず、キャッシュがそのまま使われます。明示的に refresh を呼ばれた場合のみ再検証が行われます。(数時間ページを開いたままでも更新されないのかなどは未検証です)

しかしこれでは SWR の「常に最新の状態が反映される」は実現できず、リロードするまで新しい結果は反映されません。

ここで、useFetch の第2引数、useAsyncData の第3引数である Options の中に、 initialCache というものがあります。デフォルト値は true です。

これを false にすると、ページ遷移などでコンポーネントが再度読み込まれた場合に、必ずAPIへのリクエストが行われます。

しかし、だからといって data がすぐにリセットされるわけではなく、APIリクエストが完了するまでは前回の取得結果をキャッシュとして表示し、データ取得が完了したタイミングで表示内容が更新されます。

https://zenn.dev/ytr0903/articles/6acccb5fa816ee

おまけ

useFetch 共通化したやつ。最初 key 設定せずに共通化したのを使い回して「投稿取得したつもりがユーザー情報が表示されるぞ?」みたいなことなった。

useApi.ts
type UseLazyFetch = typeof useLazyFetch

export const useApi: UseLazyFetch = (url, options) => {
  const config = useRuntimeConfig()
  return useLazyFetch(url, {
    baseURL: config.public.apiBase,
    key: url as string,
    initialCache: false,
    ...options,
  })
}

Discussion