Vue3のCompositionAPIがOptionsAPIよりも優れている理由をVue3エンジニアが解説!

Vue3のCompositionAPIがOptionsAPIよりも優れている理由をVue3エンジニアが解説!

こんにちは!

Vue2 を使用しているプロジェクトでは Options API で開発している方も多いのではないかと思います。

2020年9月に Vue3 がリリースされたこともあり、Vue 自体のアップデートも検討している方もいるのではないかと思います。

リリースされた Vue3 では主に以下の点が変更されました。

  • 軽量化
  • 処理速度の向上
  • IE の非サポート化
  • Composition API が推奨化

上記の中でも特に Vue3 の新機能である Composition API は、今後 Vue3 で開発するのであれば身につけておいて損はない技術だと思います。

今回は Vue2 の機能である Options API の問題点と Vue3 でリリースされた Composition API が優れている点について解説していきます!

はじめに

本記事では Composition API の優れている点について解説しております。

Options API を批判しているわけではなく、 Compostion API は大規模アプリケーションにおける Vue2 時点での問題点を解決することを目的とした機能のため、プロジェクトの方針や規模に応じて Options API・Composition API を使い分けることをお勧めします。

想定する読者

  • Vue2 から Vue3 へ移行する際に CompositionAPI を採用するか迷っているヒト
  • VueJS × TypeScript で開発したことがあり、CompositionAPI を使うか検討しているヒト

概要

Options APIについて

Vue2 では Options API や ClassComponent で書くことが多いのではないかと思います。

Options API においては options(data や methods、mounted など)や VueJS のライフサイクルについて基礎を把握していれば、誰が書いてもある程度秩序のあるコードを書くことができます。

import Vue from "vue";
 
export default Vue.extend({
  data() {
    return {
      name: 'John',
    };
  },
  methods: {
    doIt(): void {
      console.log(`Hello ${this.name}`);
    },
  },
  mounted() {
    this.doIt();
  },
});

Composition API について

Composition API は2020年の9月にリリースされた Vue3 の最大の機能で、コンポーネントを実装するための新しい手法です。

ロジックごとに切り出すことが可能な関数ベースの API となっております。

import { defineComponent, ref } from 'vue'
 
export default defineComponent({
  setup() {
    // data
    const name = ref('John');
    
    // methods
	  const doIt = () => console.log(`Hello ${name.value}`);
    
    // mounted
	  onMounted(() => {
	    doIt();
	  });

    return { name };
  }
});

実装上での大きな変更点はこちらでも挙げられている通り、以下になります。

  • data, computed, method 等の Vue 機能は全て setup 関数に定義
  • ライフサイクルのフックは setup 関数に定義
  • リアクティブ(変更検知)したい値は全て ref で指定必須
  • 暗黙的に動作していた部分を全て明示的に実装する必要有

これまで Options API で開発されてきた方にとっては少々戸惑いがあるかもしれませんが、 慣れてくるとComposition API のほうが書きやすく、そして得られる恩恵も多いと思っております。

ここからは Options API での懸念点や Composition API で書くことによるメリットを説明していきたいと思います。

Options API での懸念点

私が考える Options API の懸念点は下記の通りです。

  • TypeScript との相性
  • ロジックの再利用の難しさ
  • ソースコードの可読性の低下

1つずつ説明していきます。

TypeScript との相性

Vue2 では JavaScript が標準言語となって開発されていることもあって TypeScript の型推論は不完全な状態です。

Vue2 × Options API に TypeScript を導入しても thisdata , computedmethods などの options の定義が複雑で、暗黙的な部分もあるため、型定義が難しいです。

ロジックの再利用の難しさ

VueJS は SFC(単一コンポーネント)でコンポーネントごとにファイルを分けて管理することができ、直感的で書きやすいのが特徴です。 さらに Options API は data , methods , created など Options API の options を把握していれば、簡単にコンポーネントにロジックを記述することができます。

ですが、アプリケーションが大規模になってきた場合はどうでしょうか。 大規模なアプリケーションでは数百単位のコンポーネントが1つずつファイル管理されるためコードの共通化が非常に大切になってきます。

methods などで this を使っている場合、ロジックだけ切り出すことが難しく、 またコンポーネント内の View 部分に影響している場合はさらに厳しくなります。

コンポーネントが大きくなった際の可読性の悪さ

ロジックの再利用が難しくなると当然ソースコードの可読性も低下し保守の手間が増えます。

1つのコンポーネント内に複数のロジックが関与している場合、Options API では options ごとに記載するためソースコードを何度も”ジャンプ”して読み進めていかなければいけません。

また Atomic Design などの思想によりコンポーネント分割をしている場合はコンポーネント間でもソースコードを”ジャンプ”して読み進めていかなければいけないため、かなり手間がかかります。

このような懸念点はアプリケーションの規模が大きくなればなるほど問題点となり、こちらを改善するために Vue3 に追加されたのが Composition API となります。

ここからは Composition API がどのような点で優れているかについてご説明したいと思います。

Composition API が優れている点

TypeScript との相性

Vue2 では JavaScript が標準言語でしたが Vue3 で TypeScript に対応されました。

Options API では暗黙的で別途記述が必要だった部分が、 Composition API を使用することで型推論が効き開発効率が上がります。

props

setup() 関数は props コンポーネントのオプションから型を推論するため、props 引数に型をつける必要がありません。

import { defineComponent } from 'vue'

const Component = defineComponent({
  props: {
    message: {
      type: String,
      required: true
    }
  },

  setup(props) {
    const result = props.message.split('') // 正しいです, 'message' は文字列 (string) として型づけされます
    const filtered = props.message.filter(p => p.value) // エラーが起こります: Property 'filter' does not exist on type 'string'
  }
})

ref

ref は初期値から型推論します。

import { defineComponent, ref } from 'vue'

const Component = defineComponent({
  setup() {
    const year = ref(2021)

    const result = year.value.split('') // => Property 'split' does not exist on type 'number'
  }
})

算出プロパティ

値については、返り値の型から自動的に型推論されます。

import { defineComponent, ref, computed } from 'vue'

export default defineComponent({
  name: 'CounterButton',
  setup() {
    let count = ref(0)

    // 読み取り専用
    const doubleCount = computed(() => count.value * 2)

    const result = doubleCount.value.split('') // Property 'split' does not exist on type 'number'
  }
})

上記のように、明示的に型を指定することなく自動で型推論されるため自然に型安全なコードが書けるようになります。

チーム内で実装度がある程度統一されるため、開発効率の向上やレビュー時のコスト削減になります。

その他の reactive についても公式サイトで紹介されているので是非チェックしてみてください。

コードの構造化

先程、Options API において複雑に肥大化されたコンポーネントでの場合は可読性が低くなることを説明しました。

Composition API ではこちらの画像のようにロジックの関心毎に関数を分割でき、ソースコードの可読性が良くなります。

https://github.com/vuejs/rfcs/pull/42

フォームの送信やキャンセル処理のコンポーネントを例にすると、Options API の場合は、このように options ごとに分けて書くことになります。

import Vue from 'vue'
export default Vue.extend({
  name: 'FormAction',
	data() {
		return {
			/**
		   * submit
		   */

			/**
		   * cancel
		   */
		}
	},
	methods: {
		/**
	   * submit
	   */

		/**
	   * cancel
	   */
	}
})

一方、Composition API の場合は以下のようになります。
ロジックごとに分割して記述することができます。

import { defineComponent } from 'vue'

export default defineComponent({
  name: 'FormAction',
  setup() {
    /**
	   * submit
	   */

		/**
	   * cancel
	   */
  }
})

また、以下のように機能ごとにコンポジション関数にまとめ、 setup() から呼び出すことでロジックを抽出し、よりスッキリとした書き方もできるようになってます。

import { defineComponent } from 'vue'

export default defineComponent({
  name: 'FormAction',
  setup() {
		return { ...actionSubmit(), ...actionCancel() }
    /**
	   * submit
	   */

		/**
	   * cancel
	   */
  }
})

function actionSubmit() {
	/**
	 * submit
	 */
}
function actionCancel() {
	/**
	 * cancel
	 */
}

コンポーネントが肥大化してもロジックの関心毎にまとまった処理であれば、ソースコードをジャンプする回数も減り、可読性が良くなると思います。

まとめ

今回は Options API と Composition API を比較し、Composition API が優れていると思う点についてまとめてみました!

Vue3 にアップデートされたことにより TypeScript のサポートなどの懸念点が解消され、これを期にプロジェクトに取り入れたいと考える方も多いのではないかと思います。

NuxtJS の場合も年内にも Vue3 がサポートされるということもあり、今後は Composition API が標準化していくのではないかと考えております!

Vue3 や NuxtJS でのフロントエンドの開発のご相談は、ぜひお気軽にお問い合わせください。