今回使った技術
- Vue3
- Nuxt3(ベータ版)
- TypeScript
ある日の我が家
娘「ねぇ、パパ!」
娘「Vue3の、Composition APIの使い方を教えて!」
ワイ「おお、ええで〜」
ワイ「ほな、試しにこんな感じのページを作っていくで!」
娘「わー、数をカウントできるページなんだ!」
娘「便利そう〜!」
娘「しかも、2倍の数も確認できるんだね!」
ワイ「げへへ、照れるでぇ」
ワイ「ほな、さっそく作っていくで〜」
カウンターを作っていく
ワイ「まずは、カウンターの数値が今いくつなのか」
ワイ「その状態管理をせなあかんから」
<script lang="ts">
export default defineComponent({
+ data() {
+ return {
+ count: 0
+ };
+ },
})
</script>
ワイ「↑こうや!」
娘「なるほど〜」
娘「状態管理したい値は、data()っていう関数の戻り値として書くんだね!」
ワイ「せやで〜」
ワイ「そして、2倍のカウントを表示するためには・・・」
<script lang="ts">
export default defineComponent({
data() {
return {
count: 0
};
},
+ computed: {
+ double() {
+ return this.count * 2
+ }
+ },
})
</script>
ワイ「↑こうや!」
娘「countと連動した値を表示したい場合には」
娘「computedの中に関数を書けばいいんだね!」
ワイ「そうや!」
娘「パパ、HTML部分は書かなくていいの?」
ワイ「おお、せやったな!」
<template>
<h1>カウントするページ</h1>
<p>カウント:{{ count }}</p>
<p>カウント(2倍):{{ double }}</p>
<button @click="decrement">減らす</button>
<button @click="increment">増やす</button>
</template>
ワイ「↑こんな感じや!」
ワイ「ここで1回、画面を見てみよか」
ワイ「おお、できとるできとる」
娘「でも、なんかエラーが出てるよ?」
ワイ「おお、まだdecrementとincrementの関数を書いてないからやな」
ワイ「ほな、その2つの関数を書いていくで!」
<script lang="ts">
export default defineComponent({
data() {
return {
count: 0
};
},
computed: {
double() {
return this.count * 2
}
},
+ methods: {
+ increment() {
+ this.count++
+ },
+ decrement() {
+ this.count--
+ },
+ },
})
</script>
ワイ「↑こうやな!」
娘「へぇ、関数はmethodsの中に書くんだね!」
ワイ「せやで〜」
ワイ「これで完成や!」
ワイ「動かしてみるで〜」
ワイ「ボタンをポチ、ポチと」
娘「本当だ、ちゃんと数をカウントできてる〜!」
娘「これで、数を数えられないパパでも安心だね!」
ワイ「いやそこまでアホちゃうわ」
しかし娘ちゃん、思ってたのと違う
娘「・・・あれ?」
娘「でもこれ、Vue3の書き方っていうか」
娘「Vue2の書き方にそっくりじゃない?」
ワイ「せやで」
ワイ「Vue2の時からあるOptions APIの書き方やで」
娘「私が教えて欲しかったのは、Composition APIの方だよ」
ワイ「・・・せやったな」
ワイ「でも大丈夫やで」
ワイ「Options APIからComposition APIに」
ワイ「シームレスに書き換えていくこともできるからな」
娘「そうなんだ」
Composition APIに書き換えていく
ワイ「まず、状態管理したい値が書いてあるdata()の部分は」
<script setup lang="ts">
+ const count = ref(0)
</script>
<script lang="ts">
export default defineComponent({
- data() {
- return {
- count: 0
- };
- },
computed: {
double() {
return this.count * 2
}
},
methods: {
increment() {
this.count++
},
decrement() {
this.count--
},
},
})
</script>
ワイ「↑こうしてやるんや」
娘「へぇ〜」
<script setup lang="ts">
</script>
娘「↑この中に」
<script setup lang="ts">
+ const count = ref(0)
</script>
娘「↑こう書いてあげるんだ1」
ワイ「せやで」
ワイ「ほな、動作確認してみるで」
娘「え?」
娘「こんな中途半端な状態で動くの?」
ワイ「ああ、せやで」
ワイ「↑ほらな」
娘「ほんとだ、ちゃんと動いてる」
娘「へ〜」
娘「Options APIとComposition APIって、併用できるんだ」
娘「それなら、少しずつ移行できて良さそうだね!」
ワイ「せやで」
ワイ「ただ・・・」
<script setup lang="ts">
const count = ref(0)
</script>
ワイ「↑この<script setup lang="ts">の中に書いたコードが」
ワイ「data()とかcomputedとかmethodsよりも先に実行されるから」
ワイ「移していく順番は考えないとアカンみたいや」
娘「なるほどね」
computedを移行する
ワイ「次は、computedの中身を、setupの方に移していくで」
<script setup lang="ts">
const count = ref(0)
+ const double = computed(() => count.value * 2)
</script>
<script lang="ts">
export default defineComponent({
- computed: {
- double() {
- return this.count * 2
- }
- },
methods: {
increment() {
this.count++
},
decrement() {
this.count--
},
},
})
</script>
ワイ「↑こうやな!」
娘「へぇ〜」
<script setup lang="ts">
const count = ref(0)
+ const double = computed(() => count.value * 2)
</script>
娘「computedっていう関数に、関数を渡してあげる感じなんだね」
ワイ「せやで〜」
methodsを移行する
ワイ「ほな、methodsの中身も」
ワイ「setupの方に移していくで〜」
<script setup lang="ts">
const count = ref(0)
const double = computed(() => count.value * 2)
+ const increment = () => count.value++
+ const decrement = () => count.value--
</script>
<script lang="ts">
export default defineComponent({
- methods: {
- increment() {
- this.count++
- },
- decrement() {
- this.count--
- },
- },
})
</script>
ワイ「↑こうや!」
娘「へぇ〜」
娘「methodsの中にあった関数は、単純に関数を書けばいいんだね!」
ワイ「せや」
ワイ「これで、下の方の<script>タグは要らんくなるから」
<script setup lang="ts">
const count = ref(0)
const double = computed(() => count.value * 2)
const increment = () => count.value++
const decrement = () => count.value--
</script>
- <script lang="ts">
- export default defineComponent({
- })
- </script>
ワイ「↑こうやな」
ワイ「ほな、動作確認してみるで」
ワイ「よっしゃ、ちゃんと動いとるわ」
娘「わーい!」
なぜComposition APIなのか
ワイ「でも、なんでComposition APIなんてものが登場したんやろなぁ」
ワイ「Options APIの方が・・・」
- 状態管理したい値は
data()に書く - 状態と連動して表示したい値は
computedに書く - 関数は
methodsに書く
ワイ「↑こんな感じで、メッチャ分かりやすいと思うけどなぁ」
娘「それも分かるけど、私はComposition APIの方が好きだよ」
娘「状態管理する値はここ、とか」
娘「関数はここ、とか」
娘「そういう分け方じゃなく」
娘「カウンター関連の処理はここ、っていう感じで」
娘「コードをまとめることができるじゃん?」
ワイ「ああ〜、確かに」
ワイ「状態かどうか、関数かどうか、じゃなくて」
ワイ「カウンター関連の処理かどうか・・・にフォーカスを当てて」
ワイ「コードをまとめられるなぁ」
娘「うん」
娘「関心事の単位でコードをまとめれるから、私は好き」
ワイ「Options APIで書いた場合だと」
ワイ「カウンター関連の処理を修正したい場合なんかに」
ワイ「data()の中を直して、computedの中を直して、methodsの中も・・・って感じで」
ワイ「修正箇所がバラバラで、ちょっと探しにくかったもんな」
娘「そうそう」
娘「それに、このカウンター関連のロジックを」
娘「別のページでも使いたくなったときに、すごくやりやすいらしいよ」
ワイ「へぇ〜」
娘「ちょっとやって見せるね」
カウンター関連の処理を、別ファイルに切り出す
娘「さっき<script setup lang="ts">の中に書いた内容を」
export const useCounter = () => {
const count = ref(0)
const double = computed(() => count.value * 2)
const increment = () => count.value++
const decrement = () => count.value--
return {
count,
double,
increment,
decrement,
}
}
娘「↑こう、別ファイルに切り出すの」
ワイ「ほうほう」
娘「そして、ページの方から・・・」
<script setup lang="ts">
import { useCounter } from '~~/composables/count'
const { count, double, increment, decrement } = useCounter()
</script>
娘「↑こう呼び出して使ってあげるの」
ワイ「ほうほう」
娘「こうしてあげることで、同じロジックを」
娘「色んなページで使い回すこともできるよ!」
ワイ「おぉ〜、ホンマやね」
ワイ「Options APIの場合だと、その辺ちょっとやりづらかったもんなぁ」
ワイ「Mixinとか、あるにはあったけど」
娘「そうだね」
娘「つまり・・・」
- ページやコンポーネントの中から、状態関連のロジックを抽出できる
- いろんな場所で再利用できる
娘「↑こういうことが、Composition APIのおかげでやりやすくなったよね!」
ワイ「確かに・・・!」
まとめ
- Options APIの場合
- 「状態かどうか」「関数かどうか」でコードの場所が決まる
- Composition APIの場合
- 関心事の単位でコードをまとめられる
- 状態関連のロジックを抽出して、再利用できる
- Vue3でもOptions APIは使える
- Options APIとComposition APIは、1ファイルの中でも併用可能
- Options APIからComposition APIへ、動作確認しながら段階的に移行することも可能
ワイ「↑こういうことやな!」
娘「そうだね!」
〜おしまい〜
参考文献
- Composition API | Vue.js
- Quick Start - Nuxt 3
- Vue 2.xのOptions APIからVue 3.0のComposition APIへの移行で知っておくと便利なTips - ZOZO TECH BLOG
こちらの記事もよろしくやで!
-
ref()じゃなくてreactive()ってやつもあります。 ↩




