Nuxt2 asyncData を Nuxt3 defineNuxtComponent で書き換え
Nuxt.js の v2→v3 のバージョンアップにおいて、asyncData の書き換え方がわからなかったのでまとめます。
当然 useAsyncData を使って書き換えられますし、時間があるならそっちの方がいいと思いますが、自分のチームでは書き換えコスト削減のため今回は見送る予定です。
Nuxt3 では defineNuxtComponent 内で asyncData を使うことができる
Nuxt3 の defineComponent では asyncData や head を使うことができませんが、
defineNuxtComponent 内ではこれらを使うことができます。(2023年10月時点)
defineNuxtComponent() is a helper function for defining type safe Vue components using options API similar to defineComponent(). defineNuxtComponent() wrapper also adds support for asyncData and head component options.
Nuxt3(defineNuxtComponent) の asyncData は引数に context を持たない
ただし、Nuxt2 の asyncData と全く同じではありません。
具体的には、asyncData の引数として渡すことができた context を、Nuxt3 では渡せませんでした。
(チームメンバーが教えてくれました)
Nuxt3 に移行するときの書き換え方
そこで、以降 context 依存のコードの書き換え方をまとめます。
基本
defineNuxtComponent を使います。
before
<script>
/* Nuxt2 */
export default {
asyncData () {
return {
articles: [{
id: 1, title: '楽しいクリスマス'
}]
}
},
}
</script>
after
<script>
/* Nuxt3 */
export default defineNuxtComponent({
asyncData () {
return {
articles: [{
id: 1, title: '楽しいクリスマス'
}]
}
},
})
</script>
error を使っている場合
before
<script>
/* Nuxt2 */
export default {
asyncData ({ error }) {
error({
statusCode: 404,
message: 'Page Not Found',
})
},
}
</script>
after
<script>
/* Nuxt3 */
export default defineNuxtComponent({
asyncData () {
showError({
statusCode: 404,
statusMessage: 'Page Not Found'
})
},
})
</script>
plugin(app) を使っている場合
Nuxt2 の asyncData では、引数の app から plugin を参照していました。
Nuxt3 では useNuxtApp を使います。
before
<script>
/* Nuxt2 */
export default {
asyncData ({ app }) {
const greet = app.$greet()
return {
greet,
}
},
}
</script>
after
<script>
/* Nuxt3 */
export default defineNuxtComponent({
asyncData () {
const nuxtApp = useNuxtApp()
const greet = nuxtApp.$greet()
return {
greet,
}
},
})
</script>
store を使っている場合
vuex→pinia の書き換えも同時にやる場合で書いておきます。
before
<script>
/* Nuxt2 */
export default {
asyncData ({ store }) {
return {
articles: store.state.articles,
}
},
}
</script>
after
<script>
/* Nuxt3 */
import { useArticleStore } from '~/stores/articleStore'
export default defineNuxtComponent({
asyncData () {
const store = useArticleStore()
return {
articles: store.articles,
}
},
})
</script>
params を使っている場合
before
<script>
/* Nuxt2 */
export default {
asyncData ({ params }) {
return {
articleId: params.id,
}
},
}
</script>
after
<script>
/* Nuxt3 */
export default defineNuxtComponent({
asyncData () {
const route = useRoute()
const articleId = route.params.id
return {
articleId,
}
},
})
</script>
query を使っている場合
before
<script>
/* Nuxt2 */
export default {
asyncData ({ query }) {
return {
isPreview: query.preview === 'true',
}
},
}
</script>
after
<script>
/* Nuxt3 */
export default defineNuxtComponent({
asyncData () {
const route = useRoute()
const isPreview = route.query.preview === 'true'
return {
isPreview,
}
},
})
</script>
redirect を使っている場合
before
<script>
/* Nuxt2 */
export default {
asyncData ({ redirect }) {
redirect('/articles')
},
}
</script>
after
<script>
/* Nuxt3 */
export default defineNuxtComponent({
asyncData () {
navigateTo('/articles')
},
})
</script>
【注意】 defineNuxtComponent の asyncData で return した値は、lang="ts" でも型補完が効かない
見出しの通り、defineNuxtComponent 内の asyncData で定義した値は、lang="ts" の場合でも型補完が効きませんでした。(こちらもチームメンバーの方が教えてくださいました)
プロパティ 'greeting' は型 '{ $: ComponentInternalInstance; $data: {}; $props: Partial<{}> & Omit<{} & VNodeProps & AllowedComponentProps & ComponentCustomProps & Readonly<...>, never>; ... 10 more ...; $watch<T extends string | ((...args: any) => any)>(source: T, cb: T extends (...args: any) => infer R ? (args_0: R, args_1: R) => any : (...ar...' に存在しません。ts(2339)
useAsyncData で書き換えるまでは、lang="ts" 指定はしないか、 @ts-expect-error 等の対応が必要そうです。
Discussion