Nuxt3&Vue3アップデートで地味に詰まったところ
最近は細々したタスクを担当しつつ、もっぱらNuxtのアップデート作業に従事しています。
で、色々やっているうちにちょこちょこ知見も溜まってきたのでそれらをまとめてみようと思います。
変数の値
Vueのcomputed
よく使うと思います。
例えばVue2までのOptions APIで書くとこんな感じ。
<script> export default { name: 'Hoge', data() { return { hoge: 1 } }, computed: { fuga() { return this.hoge * 2; }, piyo() { return this.fuga + 1; } }, methods: { add() { this.hoge++; } } } </script> <template> <p>hoge: {{ hoge }}</p> <p>fuga: {{ fuga }}</p> <p>piyo: {{ piyo }}</p> <div> <button @click="add"> add </button> </div> </template>
hoge
の値を2倍したのがfuga
、fuga
に1足したのがpiyo
です。
ボタンをクリックするたびhoge
がインクリメントしてその他の値も変わるというコンポーネントです。
これをComposition APIで書くとこうなります。
<script setup> import { ref, computed } from 'vue'; const hoge = ref(1); const fuga = computed(() => { return hoge.value * 2; }); const piyo = computed(() => { return fuga.value + 1; }); const add = () => { hoge.value++; } </script> <template> <p>hoge: {{ hoge }}</p> <p>fuga: {{ fuga }}</p> <p>piyo: {{ piyo }}</p> <div> <button @click="add"> add </button> </div> </template>
ref
やcomputed
はRef<T>
型のref
オブジェクトを返すので.value
を付けないと値にアクセスできません。
ただ、template
の中では.value
を付けなくても値を取り出せます。最初ここで詰まりました。今でもしっくり来ていません。
加えて、defineProps()
で定義するprops
は.value
を付けなくても<script setup>
内で値にアクセスできます。なんで。
リアクティブな値はref
オブジェクトなので.value
が必要、そうでない値はそのままでアクセス可能ということでしょう。
そしてNuxt3のuseAsyncData()
の返り値のプロパティであるdata
も実はref
オブジェクトです。
型定義を見てみると以下のようになっています。
function useAsyncData( handler: (nuxtApp?: NuxtApp) => Promise<DataT>, options?: AsyncDataOptions<DataT> ): AsyncData<DataT> function useAsyncData( key: string, handler: (nuxtApp?: NuxtApp) => Promise<DataT>, options?: AsyncDataOptions<DataT> ): Promise<AsyncData<DataT>> type AsyncDataOptions<DataT> = { server?: boolean lazy?: boolean default?: () => DataT | Ref<DataT> | null transform?: (input: DataT) => DataT pick?: string[] watch?: WatchSource[] immediate?: boolean } interface RefreshOptions { dedupe?: boolean } type AsyncData<DataT, ErrorT> = { data: Ref<DataT | null> pending: Ref<boolean> execute: () => Promise<void> refresh: (opts?: RefreshOptions) => Promise<void> error: Ref<ErrorT | null> }
確かにdata
の型はRef<DataT | null>
となっています。
なのでこれも値を取り出そうとするときは.value
を付けないといけません。
useAsyncData()
でAPIを叩いてデータを取得、computed
でそのデータを元に加工して違う値を返す、なんてユースケースはよくあると思いますが、その時もdata.value
としないといけません。
これドキュメントにも書いておらず、また色んな解説記事も読みましたが書いてある記事は無かったように思います(見逃していたらすみません)。
リクエストパラメータ
Nuxt3ではNuxt2でモジュールとして提供されていたaxiosに代わってofetchが入っています。
useFetch()
やuseAsyncData()
も内部ではこのofetchを使った$fetch()
が使われています。
で、この$fetch()
なんですがリクエストの際のパラメータの設定で詰まりました。
従来のNuxt2でGETリクエストの際はURLSearchParams
を使っていたのですが、それだとクエリパラメータが上手く設定されませんでした。
Githubのissuesを見てみると違う内容の質問ですがこんなのがあったのでこのように対応しました。
export const useCustomFetch = $fetch.create({ onRequest({ options }) { if (options.params) { options.params = Object.fromEntries(options.params); } }, // 後略 });
useCustomFetch
というcomposable
を作成しました。
Object.fromEntries()
でURLSearchParams
からオブジェクトに変換して渡しています。これでGETリクエストはOKです。
POSTリクエストの場合はFormData
を使っていたのですが、こちらはそのままでも使えました。
この違いは何なんでしょうか...。
まとめ
以上、Nuxtアップデートに関連して詰まったところを挙げてみました。
個人的にはやっぱりまだしっくり来ていないところなんですが、とはいえcomposablesにロジックを切り出せるのは良いところだなとも感じるのでメリット・デメリットともにある印象です。
だいぶゴールが見えてきているので最後までしっかりやりきりたいと思います。