はじめに
今までVue2のOptionsAPIを使用してきましたが、最近Vue3のコードを読む機会がありました。
同じVueでもバージョンが異なるだけでこんなに異なるのか...と見たことない書き方に対して、どこから書き方の違いを理解していこうか困惑していました。
ですが、細かい書き方の理解より、まず何が異なるのか大枠を捉えてから、必要に応じて細かい部分を理解していったほうが良さそうだと感じたので、ここでは両者の違いとCompositionAPI特有のポイントをまとめていきます。
基本的な考え方の違い
まず、考え方の違いをインプットします。
どういうことかわからない部分もありますが、これらの考え方の違いが、実際に書き方の違いとしてどう現れるのかは後ほど理解します。
OptionsAPI
- コンポーネントのロジックが data、methods、computed、watch などの「機能ごと」に分かれて定義される
- 各機能によって定義されたプロパティは、コンポーネントのインスタンスを示す
this
によって、関数内からアクセスできる - 小規模では読みやすいが、大規模になると関連ロジックが分散して保守性が下がる
CompositionAPI
- 関連するロジックを「関心ごと」にsetup関数の中でまとめて記述できる
-
<script setup>
のなかで宣言したインポート、トップレベルの変数、トップレベルの関数は、テンプレート内で直接使うことができる - ロジックの再利用性が高く、コンポーネント間で共通のロジックを分離できる(composable関数)
- 型推論や TypeScript との親和性が高い
CompositionAPI特有の学ぶべきポイント
上記の両者の相違点より、書き方も異なる部分が複数あります。
OptionsAPIにはないCompositionAPI特有のポイントを4つ説明します。
1. setup関数
setup()
は、CompositionAPIにおいて、コンポーネントが初期化されるときに最初に実行される関数で、コンポーネントのロジック(状態・関数・ライフサイクルなど)を定義する場所です。
setup関数の引数
setup関数は2つの引数を受け取れます。
-
第一引数:
props
親コンポーネントから渡されたprops
setup 関数内の props はリアクティブで、新しい props が渡されたら更新される -
第二引数:
Setup Contextオブジェクト
3つのプロパティ(attrs, slots, emit)を持つオブジェクトで、Vueコンポーネントに関する追加のコンテキスト情報を提供する
戻り値(return)
setup() で return した変数や関数はテンプレートで直接参照可能です。
<script>
import { ref } from 'vue'
export default {
setup() {
const count = ref(0)
const increment = () => count.value++
return {
count,
increment
}
}
}
</script>
<template>
<button @click="increment">Count: {{ count }}</button>
</template>
script setup
<script setup>
はsetup関数を簡潔に書けるようにした構文で、setup関数の中身を、直接 <script>
タグの中に書けるようにした書き方です。
<script setup>
import { ref } from 'vue'
const count = ref(0)
function increment() {
count.value++
}
</script>
<template>
<button @click="increment">
{{ count }}
</button>
</template>
2. ref と reactive
CompositionAPIでは、リアクティブな状態を作る方法として、主にrefとreactiveの2つがあります。
ref()
refは、プリミティブな値(数値・文字列・真偽値など)やオブジェクトをリアクティブにするための関数です。
ref()は引数を受け取り、.value
プロパティを持つラッパーオブジェクトを返します。
const count = ref(0)
console.log(count) // { value: 0 }
console.log(count.value) // 0
テンプレート内でrefを使用するときは、.value
をつける必要はありません。
reactive()
reactiveは、オブジェクト・配列などの複合データ構造をリアクティブにするための関数です。
オブジェクト専用なので、プリミティブ型には使用できません。
refと異なりreactiveはProxyオブジェクトなので、.value
が不要でstate.count++
のように直接プロパティへアクセスできます。
<script setup>
import { reactive } from 'vue'
const state = reactive({
count: 0,
name: 'hoge'
})
const increment = () => {
state.count++
}
</script>
<template>
<p>{{ state.name }} さん:{{ state.count }}</p>
<button @click="increment">+1</button>
</template>
▼ 参考(Proxyオブジェクト)
3. ライフサイクルフック
CompositionAPIにおけるライフサイクルフックは、OptionsAPIにおけるライフサイクル(mounted, updated, destroyedなど)を関数として呼び出す形式に変わりました。
setup()
の中で Vueが用意したライフサイクル関数を直接インポートして呼び出します。
<script setup>
import { onMounted } from 'vue'
onMounted(() => {
console.log(`コンポーネントがマウントされました。`)
})
</script>
Vue3のCompositionAPIでは、Vue2にあったライフサイクルフックのうち、beforeCreateとcreatedに相当するライフサイクルフックは存在しません。
setup()がVueインスタンス初期化の直後に実行されるため、setup()の先頭で必要な処理を実行することで同等の効果が得られます。
参考:CompositionAPI ライフサイクルフック
https://ja.vuejs.org/api/composition-api-lifecycle
https://ja.vuejs.org/guide/essentials/lifecycle.html
4. Composables
CompositionAPIにはコンポーザブルという概念があります。
「コンポーザブル(composable)」とは、Composition API を活用して状態を持つロジックをカプセル化して再利用するための関数です。(compose(構成する)という英単語から来ています)。
例:カウンターのcomposable関数
import { ref } from 'vue'
export function useCounter() {
const count = ref(0)
const increment = () => count.value++
const decrement = () => count.value--
return { count, increment, decrement }
}
<script setup>
import { useCounter } from './useCounter'
const { count, increment, decrement } = useCounter()
</script>
<template>
<p>{{ count }}</p>
<button @click="increment">+1</button>
<button @click="decrement">-1</button>
</template>
最後に
OptionsAPIとCompositionAPIの何が違うのか大枠を捉えられたことで、知らない書き方を目にしたときも、両者のどのような違いから生じる差なのかを理解することができました。
「何も知らない、全く見たことがない」という状態と、「詳しくはわからないけど、何がわからないのかを理解している」状態は大きく異なり、後者の状態では自分の気持ちにかかる負荷も小さくなることを実感しました。
新しいものを学ぶ時は、すでに知っている知識との共通点・相違点を意識してインプットしていきたいです!