Nuxt.jsもついに3系がリリースされ、そろそろVueも3系にupgradeしなければ‥
とみなさんがお思いであると思いますので、公式の発表を掻い摘んでまとめていきます。
composiotion API
Vue 3.xから新たに追加された機能では有りませんが、これからはcomposition API前提での話になってきそうなので、composition APIについても簡易的にまとめておきます。
import { computed, defineComponent, reactive, } from 'vue'
export default {
components: { RepositoriesFilters, RepositoriesSortBy, RepositoriesList },
props: {
user: {
type: String,
required: true
}
},
setup(props) {
const state = reactive<State>({
todos: []
})
const result = computed(() => state.todos.sort((a, b) => {
return b.createdAt.getTime() - a.createdAt.getTime()
}))
return {
result
} // ここで返されるものはコンポーネントの他のオプションで使用可能です
}
}
setupメソッド
Options API(composition API以前の構造)と異なり、Vue component内でのdata,methods,computed,ライフサイクルメソッド(mounted,createdなど)などの区別がなくなり、全てがsetupメソッドの中に記述されています。(mounted -> onMountedなど多少の変化はあり)
一方で、componentsやpropsの記述は以前と同様に記述します。
setupメソッド内のデータは、returnされたものだけがtemplate内で使用できるようになります。
そのため、setupメソッド内でstateという変数を宣言したとしてもreturnしない場合はこれを使用することはできません。stateの値は直接使用せずに、computedを通して使用するという意図を伝えることができます。
thisの削除
全てがsetupメソッド内に記述された結果、他のプロパティにアクセスする際にthisが不要になりました。以前までのVueではこのthisの制約によりアロー関数で記述することが敬遠されていた(const self = this;など一度定義しないと内部で使用できなかったため)のですが、Composition APIではアロー関数により記述が可能になりました。
Template Directives
v-modelのデータバインディングの簡略化
v-modelを渡すだけで、親のComponentとデータバインディングするための Props 及び Emit が暗黙的にバインドされます。emitで受け取る側の処理が簡略的に書けるようになりました。
-- POINT --
v-bindの.sync修飾子とコンポーネントmodelオプションが削除され、v-modelの引数に置き換えられました。
<ChildComponent v-model:title="pageTitle" />
<!-- 上記は下記の省略形です -->
<ChildComponent :title="pageTitle" @update:title="pageTitle = $event" />
<script>
export default {
props: {
modelValue: String // vue2.xでは value:String でした
},
emits: ['update:modelValue'],
methods: {
changePageTitle(title) {
this.$emit('update:modelValue', title) // vue2.xでは this.$emit('input', title) でした
}
}
}
</script>
v-ifのkeyが不要に
v-if/v-else/v-else-ifを使用する際、keyを用いることが推奨されていましたが、Vue 3.xになって不要になりました。
<!-- Vue 2.x -->
<div v-if="condition" key="yes">Yes</div>
<div v-else key="no">No</div>
<!-- Vue 3.x -->
<div v-if="condition">Yes</div>
<div v-else>No</div>
v-forの使用する際には、v-for自体に:keyをもたせることができ、子にkeyは不要になりました。
また、Vue 2.xまではtemplateにkeyをもたせることができませんでしたが、Vue 3.xでは持たせることができ、子のkeyは省略することができます。
<!-- Vue 2.x -->
<template v-for="item in list">
<div v-if="item.isVisible" :key="item.id">...</div>
<span v-else :key="item.id">...</span>
</template>
<!-- Vue 3.x -->
<template v-for="item in list" :key="item.id">
<div v-if="item.isVisible">...</div>
<span v-else>...</span>
</template>
Vue 2.xでは、v-ifとv-forが同じ要素に設定している場合、v-forが優先されてきましたが、Vue3からはv-ifが優先されます。
v-bind
Vue 2.xの場合はすでに指定されている場合、v-bindのほうが弱かったですが、Vue 3.xでは指定する属性の順番で優先順位が変わります。
<!-- template -->
<div id="red" v-bind="{ id: 'blue' }"></div>
<!-- result -->
<div id="red"></div>
<!-- template -->
<div id="red" v-bind="{ id: 'blue' }"></div>
<!-- result -->
<div id="blue"></div>
<!-- template -->
<div v-bind="{ id: 'blue' }" id="red"></div>
<!-- result -->
<div id="red"></div>
Components
emitを明示的に定義
これまでcomponentではpropsはscript内に定義していましたが、Vue 3.xではemitも書かなくてはなりません。
これにより、途中からプロジェクトに入った人などがより速やかにコードが理解しやすくなるかと思います。
<!-- Vue 2.x -->
<template>
<div>
<p>{{ text }}</p>
<button v-on:click="$emit('accepted')">OK</button>
</div>
</template>
<script>
export default {
props: ['text']
}
</script>
<!-- Vue 3.x -->
<template>
<div>
<p>{{ text }}</p>
<button v-on:click="$emit('accepted')">OK</button>
</div>
</template>
<script>
export default {
props: ['text'],
emits: ['accepted']
}
</script>
Vue 3.x まとめ
Vue 2.xでは暗黙的に動作していた部分をVue 3.xでは定義しなくてはいけなくなるものが多く、コードの保守性が向上したのではないかと思います。ただ、そのせい?で破壊的な変更が多く(特にOption API -> composition API)、既存のVue 2.xを使用しているプロジェクトをVue 3.xに上げるのはひどく大変なものだと考えられます…
Option APIで動作自体はするようですが…
新規プロジェクトではVue 3を使ってみたいなと思います!
参考
Vue.js公式:https://v3.vuejs.org/guide/migration/introduction.html#overview