2020年9月にVue.jsではバージョン3系がリリースされました。
バージョン3系の一番の特徴といってもいいのが『Composition API』の導入だと思います。
Composition APIはVue コンポーネントの新しい形式となるもので、実装方法から記法までバージョン2系の標準であったOptions API形式とは仕様が大きく異なります。
今回はComposition APIとは何なのか、Options APIとの違いについてフロントエンド専門のプログラミング学習ツール『Skilled(スキルド)』を運営するスキルド編集部が分かりやすく解説していきます。
目次
Composition APIとは?
Compostion APIとはりアクティブな値やリアクティブな値に関連した処理をコンポーネントから分割して扱えるようにしたコンポーネントの形式です。
Composition APIではインポートされた関数を使用してコンポーネントの作成を行うことができます。
Composition APIの特徴はVue.jsの従来のコンポーネント形式であったOptions API形式との問題点を見ていくと理解がしやすいです。
Options APIの問題点とComposition APIを比較しながらみていきます。
Options API(従来のVue)の問題点
以下はOptions API で書かれたカウンターアプリのscriptブロックです。
export default {
data: () => ({
count: 0,
}),
methods: {
add() {
this.count++;
},
reduce() {
this.count--;
},
doubleUp() {
this.count = this.count * 2;
},
reset() {
this.count = 0;
},
},
};
Vue.jsを使ったことがある方であれば、慣れ親しんだscriptブロックだと思います。
このOptions API形式の問題点として
- リアクティブな値にアクセスするために、thisを経由する必要があるためmethodsでの処理をComponentのViewから切り離すことができない
- 関連要素が分散してしまう
があります。
methodsの部分のロジックを切り離して再利用したいなんてことは常々ありますがリアクティブな値にアクセスしている場合は原則的にviewから切り離せないというのがOptions APIの問題点でした。
切り離せないが故に処理が複雑なコンポーネントを作っていくとscriptブロックだけでも数百行あるような冗長化された作りになってしまいます。
また、もう一つの問題点として関連する要素が分散してしまうという問題もあります。
例えば、上記のコードにメンバーという要素が追加されて追加や削除、メンバーをソートした算出プロパティが追加されたとします。
Options APIでは、data、method、computedなどそれぞれのoptionプロパティに要素を追加していきます。
そのため、関連要素をひとまとめにすることは難しく以下のように要素が分散される作りになっており、複雑なコンポーネントになるにつれ可読性が低くなってしまう問題点があります。
mixinの欠点
Option APIでもmixinの機能を使えばdataやmethodsをまとめ再利用可能な要素と使うことは可能です。
しかし、mixinではいくつかの欠点があります。
- 不明確な要素: mixinを多様すると、コンポーネント内でどのインスタンスがmixinによって加えられているのか不明確になる。
➝ Compotison APIではrefsによりviewに依存することなくリアクティブな値が管理されるのでプロパティのソースが明確になっています。 - 名前空間のコンフリクト: 複数のmixinを利用する際に重複したプロパティキーを登録する可能性がある
➝ Composition APIでは競合するキーがある場合、非構造化変数の名前を変更することが可能です。
- mixinのthisは疎結合になっていない: mixinのthisはコンポーネントを参照するので、疎結合になっていません。コンポーネント依存関係になっているためコンポーネントを考慮した設計をする必要があります。
このような欠点は公式ドキュメントでも挙げられており、Vue3からはmixin の使用は非推奨とされています。
Composition APIを使った解決
次にComposition APIで同じ挙動のscriptブロックを書いてみます。
Composition APIではComposition Functionという機能があります。
これはコンポーネントのロジックをViewに依存せずに切り出しができる機能です。
この機能を利用してカウンターで利用する要素とメンバーで利用する要素をそれぞれ切り出し別ファイルで定義します。
上記のようにComposition APIを利用してステートフルなロジックをカプセル化することを『Composable(コンポーザブル)』と呼びます。
Composableはimportすることで簡単に呼び出しが可能です。
App.vueからimportして呼び出したコンポーネントは以下のようになります。
Options APIと比較してみるとロジックの要素を分散させることなく記述することができます。
分割し管理を行うことで関連要素が分散せずに可読性の高いコンポーネント作成しやすくなったのがCompostion APIの特徴の一つです。
Composition API の使い方
ここでは、Composition APIの使い方をOptions APIと比較しながら解説していきます。
Options APIのプロパティと比較し書き換える方法を紹介していきます。
data
Options API
data: () => ({
count: 0,
}),
Composition API
import { ref } from "vue"
const count = ref(0);
Options APIではリアクティブな値はdataオプションで定義していましたが、Composition APIではref・reactive関数を定義し使用します。
refとreactiveには以下の違いがあります。
- ref ➝ 直接アクセス可能(プリミティブ型)
- reactive ➝ オブジェクトのように 『.(ドット)』を使用してアクセスする
methods
Options API
methods: {
addCounter() {
this.count++;
},
},
Composition API
const addCounter = () => {
count.value++;
};
Options APIではmethodsオプション内に定義していましたが、Composition APIではscriptブロック内で関数定義するだけで呼び出しが可能です。
大きく変わっている点としてはリアクティブな値を変更する際の仕様です。
refで定義したリアクティブな値を変更するには .valueを利用します。
今回の例では count変数の値を変更していますが、
count.value++;
count変数のvalueにアクセスし値を変更しています。
computed
computedを利用する場合はcomputed関数を利用して定義します。
Options API
data: () => ({
count: 1,
}),
computed: {
doubleCount() {
return count * 2;
},
},
Composition API
import { ref, computed } from "vue";
const count = ref(0);
const doubleCount = computed(() => {
return count.value * 2;
});
Composition APIのcomputedはcomputed関数を使用し定義します。
computedの仕様についてはOptions APIと同様でcomputedの値は直接書き換えることは出来ません。
props
propsもOptions APIではpropプロパティを使用し定義していました。
Composition APIでは『defineProps』関数を用いてpropsを定義します。
Options API
props: {
count: {
type: Number,
required: true,
},
},
Composition API
import { ref } from "vue";
const props = defineProps({
count: { type: Number, required: true },
});
また、TypeScript環境では厳密な型定義が可能です。
props: { count: { type?: number, }, },
watch
Composition APIではwatch関数を利用することで、Options APIと同じ用にリアクティブな値を監視することができます。
Options API
watch: {
count(count, oldCount) {
console.log(count);
console.log(oldCount);
},
},
Composition API
import { ref, watch } from "vue";
const count = ref(0);
watch(count, (count, oldCOunt) => {
console.log(count);
console.log(oldCOunt);
});
ライフサイクルの利用
Composition APIでもOptions APIと同じようにライフサイクルメソッドを利用することができます。
しかし、Options APIとところどころでメソッド名が変更されているので注意が必要です。
Options APIに対応したComposition API比較したライフサイクルは以下になります。
Options API | setup 内のフック |
---|---|
beforeCreate | 不要* |
beforeCreate | 不要* |
beforeMount | onBeforeMount |
beforeMount | onBeforeMount |
beforeUpdate | onBeforeUpdate |
beforeUpdate | onBeforeUpdate |
beforeUpdate | onBeforeUpdate |
beforeUpdate | onUnmounted |
beforeUpdate | onErrorCaptured |
renderTracked | onRenderTracked |
renderTriggered | onRenderTriggered |
activated | onActivated |
onBeforeMount | onDeactivated |
利用方法はそれぞれの関数をインポートして利用することができます。
import { onMounted } from "vue";
onMounted(() => {
console.log("onMounted");
});
上記はonMountedを利用した例ですが、他のメソッドもインポートして定義すれば利用可能です。
Provide / Inject について
Composition APIと関連が深い provideとinjectについても解説しておきます。
Composition APIだけではロジックや状態を切り出したとしても複数のコンポーネント間でリアクティブな値を共有するといったことは出来ません。
例えば以下のように2つのコンポーネントで同じuseCouter composableをインポートして利用してもそれぞれのコンポーネントでuseCounterが生成されるため、コンポーネント間で情報が共有できない状態になっています。
ここで利用するのが Providerです。
以下はProviderを実装した例になります。
useCouter.ts
Composableでは、InjectionKeyを利用して参照するためのキー定義してあげます。
続いて親コンポーネントでProvideしてあげます。
こうすることで子コンポーネントからさらに深い孫コンポーネントまでuseCounterの状態を関しすることができるようになります。
App.vue
子コンポーネントではinjectを利用して親コンポーネントでProvideしたアクセスすることが可能です。
これにより親コンポーネントで更新された値は子コンポーネントにも伝わるようになり、親子間で共有ができるようになりました。
まとめ
Vue.jsではComposition APIによって『ロジックの抽出と再利用』がしやすくなりました。
コンポーネントが肥大化してしまうような複雑なアプリケーションではロジックの切り分けを行うことで、可読性の高く保守がしやすいコンポーネントを作成することが可能です。
また、Composition APIが開発されたからといってVue3ではOptions APIが非推奨になったという訳ではありません。
公式ドキュメントではOptions APIがdeprecatedになることは予定にないと明言しています。
Will Options API be deprecated?
Composition APIは自由度が高い反面設計やアーキテクチャから考えなければ活かしづらい機能でもありますので、導入する際は十分な検討が必要です。
Composition APIについてご紹介しました。
Vue.js を学ぶなら Skilled | スキルド
Skilled(スキルド)は、実践特化型のプログラミング学習サービスです。Vue.js のオフィシャルパートナーも努めており、Vue.jsが学習出来るサービスを提供しています。
あなたの学習効率を最大限スキルに転換する為に、特許技術も含め学習に関する様々な発明をしています。
マークアップからアプリケーションエンジニアまでの学習をカバーしており、コーディングしながら実践的に学習することで知識ではなく『スキル』が身につけられるサービスとなっております。
現在無料体験キャンペーンを行っていますので、気になる方はぜひ無料体験を利用してみてください。