computed(算出プロパティ)
Vue.jsを使っている人なら、computed(算出プロパティ)は使用していることでしょう。
<script>
export default {
data() {
return {
isGoodCondition: true
}
},
computed: {
conditionMessage() {
return this.isGoodCondition ? '調子いい' : '調子悪い'
}
}
}
</script>
<template>
<p>{{ conditionMessage }}</p>
</template>
使用することによってtemplate内を整頓できたり、methodsで同様のことを行うより処理を軽くできたりします。
算出プロパティ | Vue.js
https://ja.vuejs.org/guide/essentials/computed
書き込み可能な算出プロパティ
さて、それでは本題です。
computedには何らかの処理をして値を取り出す基本の使い方の他に、値をセットされた時に何らかの処理を行う機能がついています。
computed: {
hogehoge: {
// getter 関数
get() {
// 読み込み時の処理
// 通常のcomputed関数と同様の処理を書く
},
// setter 関数
set(newValue) {
// 書き込み時の処理
}
}
}
これにより、v-modelなどでcomputedの値を直接利用することが出来たりします。
<template>
<p>value:{{ value }}</p>
<p>value doubled:{{ doubledValue }}</p>
<input type="number" v-model="doubledValue">
</template>
<script>
export default {
data() {
return {
value: 5
}
},
computed: {
doubledValue: {
get() {
// value を2倍にして出力する
return this.value * 2
},
set(newValue) {
// 入力された値を1/2にしてvalueに収納する
this.value = newValue / 2
}
}
}
}
</script>
利用法1:watchを置き換える
書き込み可能な算出プロパティの有効な利用法として、watch関数を置き換えることができます。
例えば「a」を更新したときに「b」の値を同じ値に更新したい状況があったとします。
watch関数を使用すると以下の様なコードになるでしょうか。
<template>
<p>a={{ a }},b={{ b }}</p>
<input type="number" v-model="a">
</template>
<script>
export default {
data() {
return {
a: 1,
b: 1
}
},
watch: {
a(newValue) {
this.b = newValue
}
}
}
</script>
これを算出プロパティに置き換えると以下のようなコードになります。
<template>
<p>a={{ a }},b={{ b }}</p>
<input type="number" v-model="computedA">
</template>
<script>
export default {
data() {
return {
a: 1,
b: 1
}
},
computed: {
computedA: {
get() {
return this.a
},
set(newValue) {
this.a = newValue
this.b = newValue
}
}
}
}
</script>
watchを置き換えることにより、「b」がなぜ更新されたか調べる際に「computedA」を追えばよくなるので、よりコードの可視性が上がります。
また、万が一「a」のみを更新する別の機能を実装したい際などにも、watch内で面倒な例外処理を書かなくて良くなるので、より保守性があがることでしょう。
利用法2:カスタム入力フォームを作る
筆者が観測している中で最も書き込み可能な算出プロパティが使用されている例が、入力フォームをコンポーネント化することです。
<template>
<div>
<p>text: {{ text }}</p>
<custom-form v-model="text" />
</div>
</template>
<script>
import CustomForm from "./CustomForm.vue";
export default {
components: { CustomForm },
data() {
return {
text: 'sample'
}
}
}
</script>
<template>
<input type="text" v-model="computedValue">
</template>
<script>
export default {
props: [ 'modelValue' ],
emits: [ 'update:modelValue' ],
computed: {
computedValue: {
get() {
return this.modelValue
},
set(newValue) {
this.$emit('update:modelValue', newValue)
}
}
}
}
</script>
少し話は逸れますが、v-modelをコンポーネントに付与した場合、例えば上記の例の場合は以下のように展開されます。
<custom-form
:model-value="text"
@update:model-value="newValue => text = newValue"
/>
つまり、コンポーネント側では
-
propsでmodel-valueを受け取る -
emitによるイベントupdate:model-valueで値を返す
という処理を行う必要があります。
こういう場合に書き込み可能な算出プロパティを利用すると、非常に簡潔な記述で機能を実装することができます。
まとめ
算出プロパティを使うと、様々な処理が簡潔に書けたりします。
あなたが書いたそのコードを、算出プロパティで置き換えることが出来ないか、次回から是非見直してみてください。