はじめに
こんにちは🧑💻 ラボルのUIデザイナー/フロントエンドエンジニアの寺岡です。
今回はVue3から新しく使えるようになったComposition APIと、既存のOption APIの比較記事です。 Composition APIは何ができるようになったのか?どういった場面でメリットを感じるのか?を紹介していきます!
目次
どんな人向けの記事か
- Vueで開発することが多い方
- OptionAPIでしか書いたことがなく、CompositionAPIの書き方を知らない方
CompositionAPIとは?
特徴
Option(=data()
やmethods
など)を宣言する代わりに、
使用したい以下の関数をインポートして、Vueコンポーネントを作成できるようにしたもの
- Reactivity API:
ref()
・reactive()
・computed()
など - Lifecycle Hooks:
onMounted()
やonUpdated()
など - Dependency Injection:
provide()
やinject()
など
UIとロジックの切り離しが可能になった(従来はthis
に依存していたので切り離せなかった)
バージョン
- Vue3以降と2.7のversionで使える機能
- Vue2でも、@vue/composition-apiを読み込んで使用可能
CompositionAPIのメリット
OptionAPIと比較して、CompositionAPIは以下のメリットがあると感じました。
- 機能の再利用が可能
- 可読性が高くなる
- テストが簡単
countを操作する簡単なコードを例に、それぞれ比較して見ていきましょう。
機能の再利用が可能
前述したように、OptionAPIだとthis
への依存があったのでリアクティブな値を扱うロジックをcomponentから切り離すことが不可能でした。
例えば、足し算(plusCount()
)の関数を他のcomponentで使いまわしたい時に、OptionAPIだとこれ以上切り離せません。
▼OptionAPIの場合
// App.vue export default { data() { return { count: 0, diff: 1, } } methods: { // thisに依存しているため、これ以上切り離せない🤔 plusCount() { this.count = this.count + this.diff }, }, }
一方CompositionAPIだと、以下のようにモジュール用のただのjsファイルで、普通にリアクティブ関数が使えます。 「jsファイルに関数を定義できる」=「いつでも再利用できる」ということになりますね。
▼compositionAPIの場合
// useCount.js import { reactive } from "vue" export default function useCount() { // jsファイルでも、vueのリアクティブ関数が使用可能🎉 const state = reactive({ count: 0, diff: 1, }) const plusCount = () => { state.count = state.count + state.diff } return { state, plusCount, } }
↓useCount()
をVue component側で呼び出し
// App.vue import useCount from "./useCount.js" export default { setup() { // Vue component側でロジックを利用🔨 const { state, plusCount } from useCount() return { state, plusCount, } } }
可読性が高くなる
公式の「なぜ Composition API なのか?」でも提言されているように、柔軟なコード整理が可能です。
単純なロジックのcomponentでは恩恵は感じにくいですが、SFC(単一ファイルコンポーネント)のロジックが複雑化してくると、Option APIの場合ロジックのまとまりが点在する形になり、可読性が悪くなります。
以下の画像の比較を見てみましょう。count
とmessage
に関するロジックがあるとします。
- 紫: count
に関するロジック(足し算引き算やリセットなど)
- 緑: message
に関するロジック(countを変えたときにメッセージを表示する)
これはOptionAPI→CompositionAPIにリファクタリングしたcomponentのイメージなのですが、コードを同じロジックでまとめることができました。
このcomponentのロジックが複雑化していくと、OptionAPIの方はゴチャゴチャになりそうですよね。 実際に僕もOptionAPIでの開発で、ロジックが複雑なcomponentのコードを改修するときに煩わしさを感じていました。
Aのロジックに関してdata
を追加して、methods
のブロックに移動して処理を書き、
Bのロジックもdata
に戻って追加し、methods
の処理を書き...
このように、OptionAPIでは一つの機能を実現したいが、記述箇所がcomputed
やmethods
やdata
ごとにバラバラになってしまいます。
スクロールと⌘ + F
の嵐ですね。これがcompositionAPIだと記述箇所の制限がなくなるので可読性の高いコードが実現可能となります。
テストがしやすい
ここでいう「テストがしやすい」は、つまり「Jestがシンプルに使える」という定義になります。
関数のテストにJestを採用している方は多いと思いますが、Vue componentの中の関数をテストしようとしてつまずいた経験ありませんか? もちろんvue-jestのようなライブラリで可能ですが、できればそういった新規導入のコストなくプレーンなテストをしたいですよね。
前述したように、CompositionAPIだとロジックをjsファイルに切り分けられるので、Jest使ってる方はいつも通りのやり方でテスト可能です。
▼テストしたい関数
// useCount.js import { ref } from "vue" // 👇こいつをJestファイルにimportするだけ export default function useCount() { const count = ref(0) const getCalculatedCount = (diff) => { return count.value + diff } return { count, getCalculatedCount, } }
▼Jestファイル
// useCount.test.js import useCount from "./useCount.js" const { getCalculatedCount } = useCount() test("計算ロジックのテスト", () => { // 0 + 2 = 2 expect(getCalculatedCount(2)).toEqual(2) }
CompositionAPIのデメリット
一方、OptionAPIと比較して、CompositionAPIのここが惜しい!という部分です - データの参照が冗長 - 複雑なComponentじゃなければ、恩恵を感じにくい
データの参照が冗長
OptionAPIではリアクティブなデータに、一貫してthis
でアクセスしてました。
▼OptionAPI
export default { data() { return { count: 0, isShowCount: false, } }, methods: { plusCount(diff) { this.count = this.count + diff }, showCount() { this.isShowCount = true }, }, }
一方、CompositionAPIだとref
やreactive
を使うのでこんな感じです。
▼CompositionAPI
export default { setup() { const countState = reactive({ count: 0, }) const isShowCount = ref(false) const plusCount = (diff) => { // 🙂reactiveはObjectなのでこんな感じ countState.count = countState.count + diff } const showCount = () => { // 🤔refの場合、valueにアクセスする必要がある isShowCount.value = true } } }
わかりますでしょうか。
reactive関数はObjectなのは見えているのでコード通りにアクセスできますが、
ref関数を使ったリアクティブデータを参照する際、value
にアクセスする必要があるので、少し冗長に感じますね。
複雑なComponentじゃなければ、恩恵を感じにくい(Vue2の経験者のみ)
CompositionAPIは「ロジックを再利用できる」・「可読性の高いコンポーネントを作れる」といったメリットを提示しましたが、 これはあくまで複雑なロジックの時に感じられる恩恵でした。
「ロジックを再利用できる」に関しては、複数コンポーネントで再利用したいロジックがない(=各コンポーネントでロジックが完結してる)場合、恩恵は得られないですね。 「可読性の高いコンポーネントを作れる」に関しても、ロジックが1種類しかないような単純なコンポーネントであれば、OptionAPIとさほど変わりはないですね。
自身のアプリケーションのコードが、これらに当てはまるかどうかを考えてみて、CompositionAPI導入を再検討してみてもいいかもしれません。
まとめ
大枠の比較としては
- OptionAPIは制限が多く、単純なロジックのアプリケーション向き
- CompositionAPIは自由度が高く、複雑なロジックのアプリケーション向き
ということがわかりました。
選択肢としてどちらの書き方か迷ったときは、この観点で選択してみてください。
最後に
ラボルでは、エンジニアを積極採用中です。1、2年目のエンジニアから経験豊富なテックリードやエンジニリングマネージャーまで、興味がある方はぜひご応募ください!!