Composition APIとは
従来のdata, computedを用いたAPIによる問題を改善するための、Vue.jsの新たなコンポーネント作成方法です。
https://vue-composition-api-rfc.netlify.com/#summary
Vue3.xで使用可能になるとのことですが、以下のプラグインを使用することで、Vue2.xでも利用可能です。
https://github.com/vuejs/composition-api
Composition APIを利用したコンポーネントの例
<template>
<div>
<p>{{ reactiveValue }}</p>
<p>{{ computedValue }}</p>
<div>
<h1>hoge</h1>
<p>{{ hogeMethod() }}</p>
<p>{{ hogeValue }}</p>
</div>
<div>
<h1>fuga</h1>
<p>{{ fugaMethod() }}</p>
<p>{{ fugaValue }}</p>
</div>
</div>
</template>
<script lang="ts">
import {
createComponent,
computed,
reactive,
onMounted
} from '@vue/composition-api'
function hoge() {
const hogeValue = 'hoge'
const hogeMethod = () => {
return 'hogeMethod'
}
return {
hogeValue,
hogeMethod
}
}
function fuga() {
const fugaValue = 'fuga'
const fugaMethod = () => {
return 'fugaMethod'
}
return {
fugaValue,
fugaMethod
}
}
export default createComponent({
props: {
value: {
type: String,
default: ''
}
},
setup(props, context) {
onMounted(() => {
console.log('onMounted')
})
const reactiveValue = reactive('reactive value')
const computedValue = computed(() => props.value)
const hogeValue = hoge()
const fugaValue = fuga()
return {
computedValue,
reactiveValue,
...hogeValue,
...fugaValue
}
}
})
</script>
Composition APIを利用してコンポーネントを実装する
ここからは@vue/composition-api
をベースにComposition APIを見ます。
setup()
これまでプロパティに記載していたdata
, computed
, mounted
は全てsetup()の中に内包することになります。
また、template
で使用する値は全てsetup
で返却する必要があります。
import {
createComponent,
computed,
reactive,
onMounted
} from '@vue/composition-api'
setup(props, context) {
// ライフサイクルメソッドもsetup内で実装する
onMounted(() => {
console.log('onMounted')
})
const reactiveValue = reactive('reactive value')
const computedValue = computed(() => props.value)
const hogeValue = hoge()
const fugaValue = fuga()
return {
computedValue,
reactiveValue,
...hogeValue,
...fugaValue
}
}
setupのメリット
Composition APIを使用することによって、データを機能単位にまとめられるというメリットがあります。
従来のAPIでは、1つのコンポーネントが有する機能Aに対して、data
, computed
など、プロパティ単位で分割されていました。そのコンポーネントが更に機能B、Cを有する場合、機能に対するデータがあちこちに分散することで、管理が煩雑になってしまいます。
data() {
return {
機能Aのデータ,
機能Bのデータ,
機能Cのデータ
}
},
computed() {
機能Aのデータ() {...},
機能Bのデータ() {...},
機能Cのデータ() {...}
},
methods: {
...
これをComposition APIに置換することで、機能毎にデータをまとめることが出来ます
setup() {
// 機能Aに対する実装
const A = () => {...}
// 機能Bに対する実装
const B = () => {...}
// 機能Cに対する実装
const C = () => {...}
return {
A,
B,
C
}
}
setupの分割
setupにほとんどの機能を実装するということで、setupの肥大化が懸念されますが、こちらは、機能毎にfunctionを切ることで、肥大化を防止出来ます。
createComponent外で、functionを作成します。
それぞれのfunctionで、templateで使用したい値を返却するのを忘れてはいけません。
最終的には、functionの返り値をそのままsetupの返り値にしてあげます。
import {
createComponent,
computed,
reactive,
onMounted
} from '@vue/composition-api'
function hoge() {
const hogeValue = 'hoge'
const hogeMethod = () => {
return 'hogeMethod'
}
return {
hogeValue,
hogeMethod
}
}
function fuga() {
const fugaValue = 'fuga'
const fugaMethod = () => {
return 'fugaMethod'
}
return {
fugaValue,
fugaMethod
}
}
export default createComponent({
props: {
value: {
type: String,
default: ''
}
},
setup(props, context) {
onMounted(() => {
console.log('onMounted')
})
const reactiveValue = reactive('reactive value')
const computedValue = computed(() => props.value)
const hogeValue = hoge()
const fugaValue = fuga()
return {
computedValue,
reactiveValue,
...hogeValue,
...fugaValue
}
}
})
注意点として、機能分離した際の名前の衝突です。
上記例におけるhoge()
とfuga()
に同様のメソッド名がある場合、setupで最後に返却した方に上書きされます。その際には警告などが出力されないため、知らず知らずのうちに上書きが発生する。ということも考えられます。
そのため、機能分離のためのルールを設定するなど、多少人力が必要になるかもしれません。
最後に
Composition APIを用いることで、肥大化したコンポーネントで、1機能の修正のためにdata
とmethods
をスクロールで往復する状況が改善されるかもしれません。
(そもそも、そのようなコンポーネントは再設計した方がいいかもしれませんが...)
以上です。ありがとうございました。
参考記事
https://qiita.com/ryo2132/items/f055679e9974dbc3f977
https://vue-composition-api-rfc.netlify.com/#api-introduction
参考にさせていただきました。ありがとうございました。