Vue Composition API入門

Vue Composition API入門:大規模開発、ロジック再利用を加速する新しい記述スタイルを徹底解説

はじめに:Vue.jsの進化とComposition APIの登場

Vue.jsは、その直感的で分かりやすい構文と高い柔軟性から、多くの開発者に愛されているJavaScriptフレームワークです。特にOptions APIは、コンポーネントのオプション(data, methods, computed, watchなど)ごとにコードを整理するスタイルで、学習コストが低く、小〜中規模のアプリケーション開発において非常に効果的でした。

しかし、アプリケーションが大規模化し、コンポーネントの機能が複雑になるにつれて、Options APIにはいくつかの課題が顕在化してきました。

  1. 関連するロジックの分散:
    例えば、ある機能(例: ユーザーデータの取得と表示、エラーハンドリング、ローディング状態の管理)を実装する場合、関連するコードがdata, methods, computed, watch, ライフサイクルフックなど、コンポーネントオプションの各所に分散して記述されることになります。これにより、一つの機能を理解したり修正したりする際に、コンポーネント内をあちこち探し回る必要が生じ、コードの可読性や保守性が低下するという問題がありました。

  2. ロジックの再利用性の低さ:
    Options APIでは、複数のコンポーネント間で共通のロジックを再利用する際に、Mixinsという機能が提供されていました。しかし、Mixinsには「名前の衝突」「どのプロパティがMixin由来か分かりにくい」「Mixin間の依存関係が不明瞭になる」といった課題があり、大規模なプロジェクトでは管理が難しくなる傾向がありました。レンダープロップスやスコープ付きスロットといった代替手法もありましたが、これらは主にテンプレートレベルでの再利用に特化しており、JavaScriptロジック自体の再利用には向きませんでした。

  3. TypeScriptとの相性:
    Options APIは、マジックストリングや暗黙的なthisの型に依存する部分が多く、TypeScriptによる型推論の恩恵を十分に受けることが難しい場面がありました。これにより、大規模なアプリケーション開発において、Typescriptによる堅牢な型付けやコード補完のメリットを最大限に活かしきれないという課題がありました。

これらの課題に対処するために、Vue 3から導入されたのが Composition API です。Composition APIは、コンポーネントのロジックを機能ごとに整理し、記述するための新しいスタイルを提供します。これにより、関連するコードをひとまとめにでき、ロジックの再利用が容易になり、TypeScriptとの相性も向上します。

Composition APIは、Options APIを置き換えるものではなく、Options APIと共存、あるいは選択できる新しい記述スタイルとして提供されています。Vue 3以降では、Options APIとComposition APIのどちらを選択するか、あるいは両方を組み合わせて使用するかは開発者の判断に委ねられます。しかし、特に大規模なアプリケーションや、ロジックの再利用が頻繁に発生するプロジェクトにおいては、Composition APIが非常に有効な選択肢となります。

この記事では、Composition APIの基本的な考え方から、主要なAPI (ref, reactive, computed, watch, watchEffect, ライフサイクルフック) の使い方、ロジック再利用のためのテクニック (Composables)、Options APIとの比較と共存、TypeScriptとの連携、そして実践的なコード例まで、Composition APIを体系的に理解し、使いこなせるようになるための詳細な解説を行います。

さあ、Vue.js開発を次のレベルに引き上げるComposition APIの世界へ飛び込みましょう。

1. Composition APIの基本概念:setup 関数

Composition APIの中心となるのは、コンポーネントオプションの一つとして追加された新しい関数、setup 関数です。コンポーネントのリアクティブな状態、算出プロパティ、ウォッチャー、メソッド、ライフサイクルフックなど、Composition APIで記述するほとんどのロジックは、この setup 関数内に記述されます。

setup 関数は、コンポーネントインスタンスが生成される前に実行されます。つまり、Options APIの beforeCreatecreated フックよりも前に実行されることになります。

setup 関数は、以下の2つの引数を受け取ることができます。

  1. props: コンポーネントに渡されたリアクティブなプロパティです。これはリアクティブなオブジェクトであり、プロパティが更新されると自動的に変更が追跡されます。ただし、props オブジェクト自体を分割代入したり、破壊的に変更したりすると、リアクティブ性が失われる可能性があるため注意が必要です。(推奨されるのは、toRefs を使用して分割代入する方法です。これについては後述します。)
  2. context: いくつかのユーティリティプロパティを含む通常の(非リアクティブな)オブジェクトです。Vue 3.3以降では非推奨になりましたが、以前は以下のプロパティを含んでいました。
    • attrs: コンポーネントに渡された属性のうち、propsとして宣言されていないもの。
    • slots: スロットとして渡されたコンテンツ。
    • emit: 親コンポーネントにイベントを発行するための関数。
    • expose: テンプレート参照(ref)で親コンポーネントに公開するプロパティを定義するための関数。

Vue 3.3以降では、emit 関数は defineEmits マクロを使用することが推奨されており、attrsslotsuseAttrs および useSlots 関数として Composition API から直接インポートして使用することが推奨されています。したがって、現代的なコードでは context 引数を使う機会は減っています。

setup 関数は、以下のいずれかを返す必要があります。

  1. オブジェクト: setup 関数から返されたオブジェクトのプロパティは、テンプレートやコンポーネントインスタンスの他のオプション (computed, methods など、ただしOptions APIとComposition APIの併用時) から利用可能になります。テンプレート内で使用したいデータや関数は、このオブジェクトに含めて返します。
  2. レンダー関数: コンポーネントのレンダー関数を直接返すことも可能です。これはJSXやテンプレートエンジンを使用しない場合に用いられます。

最も一般的なケースは、テンプレートで使用するデータや関数をオブジェクトとして返す方法です。

“`vue

“`

この例では、setup 関数内で ref(0) を使用してリアクティブな数値 count を宣言し、increment 関数を定義しています。これらの値や関数は、setup 関数から返されたオブジェクトに含まれており、テンプレート内で {{ count }}@click="increment" のように参照できるようになっています。

2. リアクティブ性の基礎:refreactive

Composition APIにおいて、コンポーネントの状態をリアクティブにするために主に使われるAPIは refreactive です。これらはVueのリアクティブシステムの中核を担います。

ref

ref は、任意の型の値(プリミティブ型やオブジェクト)をリアクティブな参照(Reference)オブジェクトにラップするために使用されます。ref で作成されたオブジェクトは、.value プロパティを持ち、この .value プロパティを通してリアクティブな値にアクセスしたり、変更したりします。

“`javascript
import { ref } from ‘vue’;

// 数値をリアクティブにする
const count = ref(0);
console.log(count.value); // 0

// 文字列をリアクティブにする
const name = ref(‘Vue’);
console.log(name.value); // ‘Vue’

// オブジェクトをリアクティブにする
const state = ref({ id: 1, name: ‘test’ });
console.log(state.value.name); // ‘test’

// 配列をリアクティブにする
const list = ref([1, 2, 3]);
console.log(list.value[0]); // 1

// 値の変更
count.value++; // count.value は 1 になる
state.value.name = ‘updated’; // state.value.name は ‘updated’ になる
list.value.push(4); // list.value は [1, 2, 3, 4] になる
“`

テンプレート内では、ref でラップされたオブジェクトは自動的にアンラップされるため、.value を書く必要はありません。

“`vue

“`

また、reactive オブジェクトのプロパティとして ref が使われた場合も、.value なしでアクセスできます。

“`javascript
import { ref, reactive } from ‘vue’;

const state = reactive({
count: ref(0) // reactiveオブジェクトのプロパティにrefを使う
});

console.log(state.count); // 0 (自動的にアンラップされる)
console.log(state.count.value); // 0 (直接 .value でもアクセス可能)

state.count++; // 値を変更する場合も .value なしでOK
console.log(state.count); // 1
“`

reactive

reactive は、オブジェクト(または配列)をリアクティブなプロキシ(Proxy)オブジェクトに変換するために使用されます。reactive はプリミティブ型(文字列、数値、真偽値、null, undefined, Symbol, BigInt)を直接リアクティブにすることはできません。オブジェクト内のプロパティへのアクセスや変更が追跡されます。

“`javascript
import { reactive } from ‘vue’;

// オブジェクトをリアクティブにする
const state = reactive({
count: 0,
name: ‘Vue’
});

console.log(state.count); // 0
console.log(state.name); // ‘Vue’

// 値の変更
state.count++; // state.count は 1 になる
state.name = ‘Composition API’; // state.name は ‘Composition API’ になる

// 配列をリアクティブにする
const list = reactive([1, 2, 3]);
list.push(4); // list は [1, 2, 3, 4] になる
“`

reactive で作成されたオブジェクトは、ref とは異なり、.value プロパティを持ちません。プロキシされたオブジェクトに直接アクセスします。

reactive の注意点:

  • プリミティブ型: reactive はプリミティブ型を扱えません。プリミティブ型をリアクティブにする場合は ref を使用します。
    javascript
    // これはリアクティブになりません!
    const notReactive = reactive(1);
  • 分割代入: reactive オブジェクトを分割代入すると、リアクティブ性が失われます。分割代入された変数は通常の変数となり、元のリアクティブオブジェクトとの関連がなくなります。
    “`javascript
    const state = reactive({ count: 0, name: ‘Vue’ });

    // 分割代入 – リアクティブ性が失われる
    let { count, name } = state;

    count++; // state.count は 0 のまま
    console.log(state.count); // 0
    console.log(count); // 1
    この問題を解決するために、`toRefs` や `toRef` が使用されます(後述)。
    * **既存の変数への再代入:** `reactive` オブジェクト全体を新しいオブジェクトに再代入すると、元のプロキシオブジェクトとの関連が失われ、リアクティブ性が失われる場合があります。
    javascript
    let state = reactive({ count: 0 });

    // リアクティブ性は失われる可能性がある
    state = reactive({ count: 1 });
    ``
    可能な限り、
    reactive` オブジェクト内のプロパティを直接変更するようにします。

ref vs reactive の使い分け

  • ref:

    • プリミティブ型を含む、あらゆる型の値をリアクティブにしたい場合に適しています。
    • 単一の値をリアクティブにしたい場合にシンプルです。
    • reactive オブジェクトのプロパティとして使用した場合、自動的にアンラップされるため扱いやすいです。
    • 分割代入しても .value を介して元の ref オブジェクトへの参照が保たれるため、リアクティブ性が維持されます。(ただし、テンプレートで分割代入された ref を使う場合は、toRefs が必要になることがあります)
  • reactive:

    • オブジェクトや配列をリアクティブにしたい場合に適しています。
    • 複数の関連するプロパティを持つ状態を一つのオブジェクトとして管理したい場合に、より構造的に記述できます。
    • 分割代入するとリアクティブ性が失われる点に注意が必要です。

一般的には、単一の値を扱う場合は ref、複数の関連するプロパティを持つ状態を扱う場合は reactive を使うことが多いです。しかし、ref はオブジェクトもラップできるため、すべてを ref で統一するというスタイルも可能です。(例: const state = ref({ count: 0, name: 'Vue' })
どちらを選ぶかはチームや個人の好みにもよりますが、それぞれの特性を理解して適切に使い分けることが重要です。

toRefstoRef

前述のように、reactive オブジェクトを分割代入するとリアクティブ性が失われるという問題がありました。この問題を解決するのが toRefs および toRef です。

  • toRefs:
    toRefs は、reactive オブジェクトの各プロパティを個別の ref オブジェクトに変換します。これにより、reactive オブジェクトを分割代入しても、各プロパティが ref としてリアクティブ性を保つことができます。

    “`javascript
    import { reactive, toRefs } from ‘vue’;

    const state = reactive({
    count: 0,
    name: ‘Vue’
    });

    // toRefs を使って各プロパティを ref に変換し、分割代入
    const stateAsRefs = toRefs(state); // stateAsRefs は { count: Ref, name: Ref } となる
    let { count, name } = stateAsRefs; // count と name はそれぞれ ref オブジェクトになる

    console.log(count.value); // 0
    console.log(name.value); // ‘Vue’

    // ref の値を変更すると、元の reactive オブジェクトも更新される
    count.value++;
    name.value = ‘Composition API’;

    console.log(state.count); // 1
    console.log(state.name); // ‘Composition API’

    console.log(count.value); // 1
    console.log(name.value); // ‘Composition API’
    ``setup関数内でreactiveオブジェクトを宣言し、そのプロパティをテンプレートで使用したい場合に、toRefsを使ってオブジェクトを返すことで、テンプレート内で.value` なしでアクセスできるようになりつつ、分割代入のメリット(プロパティ名で直接アクセスできる)を享受できます。

    “`vue


    ``
    この例では、テンプレート内で
    countname.valueなしで参照できます。これは、toRefs(state){ count: Ref, name: Ref }のようなオブジェクトを返し、それをスプレッド構文で展開しているためです。テンプレートはこのref` オブジェクトを自動的にアンラップします。

  • toRef:
    toRef は、toRefs がオブジェクト全体のプロパティを変換するのに対し、特定の単一のプロパティのみを ref に変換したい場合に使用します。これは、主に props から特定のプロパティを ref として抽出したい場合などに便利です。

    “`javascript
    import { reactive, toRef } from ‘vue’;

    const state = reactive({
    count: 0,
    name: ‘Vue’
    });

    // state オブジェクトの count プロパティのみを ref に変換
    const countRef = toRef(state, ‘count’);

    console.log(countRef.value); // 0

    // countRef.value を変更すると state.count も更新される
    countRef.value++;
    console.log(state.count); // 1

    // state.count を変更すると countRef.value も更新される
    state.count++;
    console.log(countRef.value); // 2
    ``propsを扱う場合にもtoRefは便利です。setupの引数propsはリアクティブオブジェクトですが、そのまま分割代入するとリアクティブ性が失われます。toRefを使うことで、特定のpropをリアクティブなref` として抽出できます。

    “`vue


    “`

3. 算出プロパティ:computed

computed は、他のリアクティブな状態に依存して、新しいリアクティブな値を生成するために使用されます。これはOptions APIの computed オプションと同様の機能を提供しますが、関数として記述します。

computed は、引数としてゲッター関数を受け取り、リアクティブな算出参照(Computed Ref)を返します。算出参照は .value を通じて値にアクセスできます。算出参照の値は、依存するリアクティブな状態が変更された場合にのみ再計算されます。

“`javascript
import { ref, computed } from ‘vue’;

const count = ref(0);

// count に依存する算出プロパティ
const doubledCount = computed(() => count.value * 2);

console.log(doubledCount.value); // 0

count.value++; // count が変更される
console.log(doubledCount.value); // 2 (再計算された値)
“`

computed は、ゲッター関数だけでなく、セッター関数も含むオブジェクトを受け取ることもできます。これにより、算出プロパティに対して値を代入する(書き込む)ことが可能になります。

“`javascript
import { ref, computed } from ‘vue’;

const firstName = ref(‘John’);
const lastName = ref(‘Doe’);

// getter と setter を持つ算出プロパティ
const fullName = computed({
// ゲッター: firstName と lastName に依存して文字列を生成
get: () => firstName.value + ‘ ‘ + lastName.value,
// セッター: 新しい値が代入されたときに、firstName と lastName を更新
set: (newValue) => {
const names = newValue.split(‘ ‘);
firstName.value = names[0];
lastName.value = names[names.length – 1];
}
});

console.log(fullName.value); // “John Doe”

// fullName に値を代入すると、セッターが実行される
fullName.value = ‘Jane Smith’;

console.log(firstName.value); // “Jane”
console.log(lastName.value); // “Smith”
“`

computed は、複数のリアクティブな状態に依存させることができます。依存関係はVueのリアクティブシステムによって自動的に追跡されます。

“`javascript
import { ref, reactive, computed } from ‘vue’;

const item = reactive({ price: 100, quantity: 1 });
const discount = ref(10); // 10円引き

const totalPrice = computed(() => {
// item.price, item.quantity, discount.value に依存
return item.price * item.quantity – discount.value;
});

console.log(totalPrice.value); // 100 * 1 – 10 = 90

item.quantity = 2; // item.quantity 変更 -> totalPrice 再計算
console.log(totalPrice.value); // 100 * 2 – 10 = 190

discount.value = 20; // discount 変更 -> totalPrice 再計算
console.log(totalPrice.value); // 100 * 2 – 20 = 180
“`

computed を使用することで、テンプレート内で複雑な計算ロジックを記述することなく、状態に基づいて自動的に更新される値を簡単に作成できます。これは、テンプレートの可読性を高め、コードをより宣言的に保つのに役立ちます。

4. ウォッチャー:watchwatchEffect

ウォッチャーは、特定のリアクティブな値が変更されたことを検知し、それに応じて副作用(Side Effect)を実行するために使用されます。副作用の例としては、APIコールの実行、DOMの操作、他の状態の変更などがあります。Composition APIでは、watchwatchEffect という2つのウォッチャーAPIが提供されています。

watch

watch は、Options APIの watch オプションと同様の機能を提供します。特定のリアクティブなデータソース(単一の refreactive オブジェクト、算出プロパティなど)を明示的に監視し、変更が発生したときにコールバック関数を実行します。

watch 関数は、以下の引数を受け取ります。

  1. 監視対象: 監視したいデータソースを指定します。以下のいずれか、またはそれらの配列を指定できます。
    • ref
    • reactive オブジェクト
    • 算出プロパティ (computed)
    • ゲッター関数 (() => source.property)
  2. コールバック関数: 監視対象が変更されたときに実行される関数です。この関数は、新しい値 (newValue) と古い値 (oldValue) を引数として受け取ります。
  3. オプション (省略可能): ウォッチャーの動作をカスタマイズするためのオプションオブジェクトです。一般的なオプションには以下があります。
    • immediate: ウォッチャーの作成時に、コールバック関数をすぐに一度実行するかどうか(デフォルトは false)。
    • deep: 監視対象がオブジェクトまたは配列の場合、その内部の変更も再帰的に追跡するかどうか(デフォルトは false)。reactive オブジェクトを直接監視する場合は、デフォルトでdeep監視が有効になります。
    • flush: コールバックの実行タイミングを指定します('pre' (デフォルト), 'post', 'sync')。'post' はDOM更新後に実行されるため、DOMへのアクセスが必要な場合に便利です。

watch の使い方例:

  • 単一の ref を監視:
    “`javascript
    import { ref, watch } from ‘vue’;

    const count = ref(0);

    watch(count, (newValue, oldValue) => {
    console.log(count が ${oldValue} から ${newValue} に変更されました。);
    });

    count.value++; // コンソール出力: “count が 0 から 1 に変更されました。”
    “`

  • ゲッター関数を監視:
    reactive オブジェクトの特定のプロパティを監視したい場合や、複数の値を組み合わせて監視したい場合などに便利です。
    “`javascript
    import { reactive, watch } from ‘vue’;

    const state = reactive({ count: 0, name: ‘Vue’ });

    // state.count プロパティのみを監視
    watch(
    () => state.count, // ゲッター関数を指定
    (newValue, oldValue) => {
    console.log(state.count が ${oldValue} から ${newValue} に変更されました。);
    }
    );

    state.count++; // コンソール出力: “state.count が 0 から 1 に変更されました。”
    state.name = ‘Composition API’; // これは監視されない
    “`

  • 複数のデータソースを監視:
    監視対象の配列を指定します。コールバック関数の引数は、新しい値の配列と古い値の配列になります。
    “`javascript
    import { ref, watch } from ‘vue’;

    const count = ref(0);
    const name = ref(‘Vue’);

    // count と name の両方を監視
    watch([count, name], ([newCount, newName], [oldCount, oldName]) => {
    console.log(count: ${oldCount} -> ${newCount}, name: ${oldName} -> ${newName});
    });

    count.value++; // コンソール出力: “count: 0 -> 1, name: Vue -> Vue”
    name.value = ‘Composition API’; // コンソール出力: “count: 1 -> 1, name: Vue -> Composition API”
    “`

  • reactive オブジェクトを監視:
    reactive オブジェクトを直接監視すると、デフォルトで deep 監視が有効になります。オブジェクト内のどのプロパティが変更されてもコールバックが実行されます。
    “`javascript
    import { reactive, watch } from ‘vue’;

    const state = reactive({ count: 0, nested: { name: ‘Vue’ } });

    // reactive オブジェクト全体を監視(deep: true が暗黙的に適用される)
    watch(state, (newState, oldState) => {
    // 注意: newState と oldState はどちらも同じ Proxy オブジェクトを参照する可能性があるため、
    // オブジェクトの中身を比較する場合はディープコピーなどが必要になる場合がある
    console.log(‘state が変更されました。’);
    console.log(‘New state:’, newState);
    console.log(‘Old state (注意: 同じオブジェクトを参照する場合がある):’, oldState);
    });

    state.count++; // コンソール出力: “state が変更されました。” …
    state.nested.name = ‘Composition API’; // コンソール出力: “state が変更されました。” …
    ``reactiveオブジェクトの変更を正確に古い値と比較したい場合は、監視対象をゲッター関数にし、deep: true` オプションを指定する方が安全です。

    “`javascript
    import { reactive, watch } from ‘vue’;
    import lodash from ‘lodash’; // 例としてディープコピーライブラリを使用

    const state = reactive({ count: 0, nested: { name: ‘Vue’ } });

    watch(
    () => lodash.cloneDeep(state), // ゲッター関数で現在の state のコピーを返す
    (newState, oldState) => {
    console.log(‘state が変更されました。’);
    console.log(‘New state (コピー):’, newState);
    console.log(‘Old state (コピー):’, oldState);
    },
    { deep: true } // deep オプションを明示的に指定
    );

    state.count++; // コンソール出力: “state が変更されました。” … newState/oldState は期待通り
    state.nested.name = ‘Composition API’; // コンソール出力: “state が変更されました。” … newState/oldState は期待通り
    ``
    ただし、ゲッター関数でコピーを返す方法はパフォーマンスコストがかかる可能性があるため、必要な場合のみ使用します。通常は、
    reactive` オブジェクト全体を監視するか、特定のプロパティをゲッター関数で監視することが多いです。

  • オプションの使用例 (immediate, deep, flush):
    “`javascript
    import { ref, watch } from ‘vue’;

    const data = ref({ value: ‘initial’ });

    watch(
    data,
    (newValue, oldValue) => {
    console.log(Value: ${newValue.value}); // deep: true のため newValue.value にアクセス
    },
    { immediate: true, deep: true, flush: ‘post’ } // オプションを指定
    );

    // immediate: true のため、コンポーネント作成時にすぐにコールバックが実行される
    // “Value: initial” が出力される

    data.value.value = ‘changed’; // deep: true のためオブジェクト内部の変更も検知される
    // DOM更新後にコールバックが実行される (flush: ‘post’)
    // “Value: changed” が出力される
    “`

watchEffect

watchEffectwatch よりもシンプルで、自動的な依存関係追跡に特化しています。コールバック関数内で参照されたすべてのリアクティブな状態を自動的に監視し、それらのいずれかが変更されるたびにコールバック関数を再実行します。

watchEffect は引数としてコールバック関数を受け取ります。このコールバック関数は、watchEffect の作成時に一度すぐに実行され、その後、コールバック関数内で参照されたリアクティブな状態が変更されるたびに再実行されます。

“`javascript
import { ref, watchEffect } from ‘vue’;

const count = ref(0);
const name = ref(‘Vue’);

watchEffect(() => {
// このコールバック関数内で count.value と name.value が参照されている
// -> count と name の両方が監視対象となる
console.log(現在の count: ${count.value}, name: ${name.value});
});

// watchEffect の作成時に一度実行される: “現在の count: 0, name: Vue”

count.value++; // count の変更 -> コールバックが再実行される
// “現在の count: 1, name: Vue”

name.value = ‘Composition API’; // name の変更 -> コールバックが再実行される
// “現在の count: 1, name: Composition API”
“`

watchEffect は、watch のように明示的に監視対象を指定したり、古い値と新しい値を受け取ったりすることはありません。単に「コールバック内のリアクティブな状態が変更されたら再実行」というシンプルな挙動です。

watchEffect は、以下のオプションオブジェクトを第2引数として受け取ることができます。

  • flush: コールバックの実行タイミングを指定します('pre' (デフォルト), 'post', 'sync')。
  • onInvalidate: コールバックが再実行される前、またはウォッチャーが停止される前に実行されるクリーンアップ関数を登録します。非同期処理などで保留中の副作用をキャンセルしたい場合に便利です。

“`javascript
import { ref, watchEffect } from ‘vue’;

const userId = ref(1);

watchEffect(async (onInvalidate) => {
console.log(ユーザーID ${userId.value} のデータを取得します...);

let canceled = false; // キャンセルフラグ
onInvalidate(() => {
// コールバックが再実行されるか、ウォッチャーが停止される前に実行される
canceled = true; // キャンセルフラグを立てる
console.log(ユーザーID ${userId.value} の取得処理をキャンセルします。);
});

try {
// 非同期処理(例: APIコール)
const response = await fetch(https://api.example.com/users/${userId.value});
// fetch の結果を処理
if (!canceled) { // キャンセルされていなければ処理を続ける
const data = await response.json();
console.log(‘データ取得成功:’, data);
}
} catch (error) {
if (!canceled) {
console.error(‘データ取得エラー:’, error);
}
}
});

// ウォッチャー作成時: “ユーザーID 1 のデータを取得します…” -> APIコール -> “データ取得成功: …”

userId.value = 2; // userId を変更

// userId.value が変更されたため、コールバックが再実行される
// 再実行の前に onInvalidate で登録した関数が実行される: “ユーザーID 1 の取得処理をキャンセルします。”
// 新しいコールバックが実行される: “ユーザーID 2 のデータを取得します…” -> APIコール -> “データ取得成功: …”
``
この例では、ユーザーIDが変更されるたびに新しいデータを取得しますが、前回の取得処理が完了する前にIDが再変更された場合、
onInvalidate` 関数が実行されて前回の処理をキャンセルし、古いデータでUIが更新されてしまうといった問題を回避できます。

watchwatchEffect の使い分け

  • watch:

    • 監視対象を明示的に指定したい場合
    • 新しい値と古い値にアクセスしたい場合
    • 特定のデータソースの変更に対してのみ副作用を実行したい場合(不要な再実行を避けたい場合)
    • 初期実行を制御したい場合(immediate オプション)
  • watchEffect:

    • コールバック内で参照されたリアクティブな状態すべてに反応して副作用を実行したい場合
    • 古い値が必要ない場合
    • 監視対象を自分で管理するのが面倒な場合(自動追跡に任せたい場合)
    • クリーンアップ処理が必要な非同期副作用を実行する場合(onInvalidate

一般的に、特定のデータソースの変更に反応して副作用を実行する場合は watch を、コールバック内のリアクティブな状態が変更されたらとにかく再実行したい場合は watchEffect を使用します。

5. ライフサイクルフック

Composition APIでは、Options APIのライフサイクルフックに対応する関数が提供されています。これらの関数は、setup 関数内でインポートして使用します。

これらの関数は、setup 関数の実行コンテキスト内で呼び出す必要があります。つまり、setup 関数から返される同期的な関数内や、非同期処理の後に呼び出すことはできません。(非同期処理内でフックを呼び出す場合は、awaitの前に呼び出す必要があります。)

Options API Hook Composition API Hook 説明
beforeCreate N/A setup 関数自体がこれに対応します。
created N/A setup 関数自体がこれに対応します。
beforeMount onBeforeMount コンポーネントがDOMにマウントされる直前に実行されます。
mounted onMounted コンポーネントがDOMにマウントされた後(初回レンダリング後)に実行されます。DOMアクセスが必要な処理に適しています。
beforeUpdate onBeforeUpdate リアクティブな状態が変更され、コンポーネントがDOMを更新する直前に実行されます。
updated onUpdated コンポーネントがDOMを更新した後(再レンダリング後)に実行されます。DOMアクセスが必要な処理に適しています。
beforeUnmount onBeforeUnmount コンポーネントがアンマウント(DOMから削除)される直前に実行されます。クリーンアップ処理(イベントリスナーの削除など)に適しています。
unmounted onUnmounted コンポーネントがアンマウントされた後に実行されます。クリーンアップ処理に適しています。
errorCaptured onErrorCaptured 子孫コンポーネントから伝搬されたエラーを捕捉します。
renderTracked onRenderTracked (開発モードのみ) コンポーネントのレンダーでリアクティブな依存関係が追跡されたときに呼び出されます。デバッグに役立ちます。
renderTriggered onRenderTriggered (開発モードのみ) リアクティブな依存関係によってコンポーネントが再レンダリングを引き起こしたときに呼び出されます。デバッグに役立ちます。
activated onActivated <KeepAlive> コンポーネントによってキャッシュされたコンポーネントがアクティブになったときに呼び出されます。
deactivated onDeactivated <KeepAlive> コンポーネントによってキャッシュされたコンポーネントが非アクティブになったときに呼び出されます。
serverPrefetch onServerPrefetch (SSRのみ) サーバー側レンダリングの前に非同期データをプリフェッチします。

各ライフサイクルフック関数は、コールバック関数を引数として受け取ります。このコールバック関数が、それぞれのタイミングで実行されます。

“`vue

``onMountedフックは、コンポーネントが初期レンダリングされてDOMにマウントされた後に実行されるため、テンプレート参照(後述)を使ってDOM要素にアクセスしたり、外部ライブラリを初期化したり、非同期データを取得したりするのに適しています。onUnmountedフックは、コンポーネントがDOMから削除される直前に実行されるため、onMounted` や他の場所で登録したイベントリスナー、タイマー、ネットワーク接続などをクリーンアップするのに非常に重要です。これによりメモリリークを防ぎます。

ライフサイクルフックは、特定の機能に関連するロジック(例: データ取得とクリーンアップ)を setup 関数内でまとめて記述できるため、Options APIよりもコードが整理されやすくなります。

6. ロジックの再利用:Composables

Composition APIの最も強力な利点の一つは、ロジックの再利用を簡単かつ効果的に行える点です。Options APIのMixinsが抱えていた課題を解決するために、「Composables」というパターンが生まれました。

Composablesは、単なる関数です。この関数内でComposition APIの機能(ref, reactive, computed, watch, ライフサイクルフックなど)を使用して状態管理やロジックを記述し、必要なリアクティブな状態や関数を返します。

Composablesの基本的な考え方:

  • コンポーネントの setup 関数内で記述された特定の機能に関するロジック(例: マウス位置追跡、APIからのデータフェッチ、フォームバリデーション)を独立した関数として切り出す。
  • 切り出された関数(Composable)は、通常 use という接頭辞をつけて命名する慣習があります(例: useMousePosition, useFetchData, useFormValidation)。
  • Composable関数内で、必要なリアクティブな状態や算出プロパティ、ウォッチャー、ライフサイクルフックなどを定義する。
  • Composable関数から、コンポーネントで使用したい状態や関数をオブジェクトとして返す。
  • コンポーネントの setup 関数内でその Composable 関数を呼び出し、返された状態や関数を使用する。

Composableの例:マウス位置追跡

マウスカーソルのX, Y座標を追跡するロジックを Composable として切り出してみましょう。

“`javascript
// src/composables/useMousePosition.js
import { ref, onMounted, onUnmounted } from ‘vue’;

// 慣習として use 接頭辞をつける
export function useMousePosition() {
const x = ref(0);
const y = ref(0);

// マウス移動時のイベントハンドラー
function update(e) {
x.value = e.pageX;
y.value = e.pageY;
}

// コンポーネントがマウントされたらイベントリスナーを追加
onMounted(() => {
window.addEventListener(‘mousemove’, update);
});

// コンポーネントがアンマウントされたらイベントリスナーを削除
onUnmounted(() => {
window.removeEventListener(‘mousemove’, update);
});

// コンポーネントで使用したいリアクティブな状態を返す
return { x, y };
}
“`

この Composable 関数 useMousePosition は、ref でリアクティブな xy を宣言し、onMounted でイベントリスナーを追加し、onUnmounted でクリーンアップしています。そして、追跡している座標 x, y を返しています。

この Composable をコンポーネントで使用する例:

“`vue

``
これで、どのコンポーネントでも
useMousePosition` をインポートして呼び出すだけで、マウス位置追跡ロジックを簡単に再利用できます。Mixinsのような名前衝突の心配もなく、どの状態や関数が Composable 由来なのかも明確です。

Composablesのメリット:

  • 関連ロジックの集約: 特定の機能に関するリアクティブな状態、算出プロパティ、ウォッチャー、ライフサイクルフックなどが一つの関数内にまとめられるため、コードの可読性と保守性が向上します。
  • 強力な再利用性: コンポーネント間で複雑なロジックを簡単に共有できます。
  • 名前衝突の回避: Mixinsと異なり、Composablesは通常の関数呼び出しなので、返されるプロパティの名前は呼び出し側で自由に命名できます。
  • 明確な依存関係: Composable がどの Composition API 関数(ref, onMounted など)を使用しているかがコードから明確に分かります。
  • TypeScriptとの相性: Composable は通常の関数なので、引数や戻り値に型定義を簡単に追加でき、TypeScriptの恩恵を最大限に受けられます。

Composablesは、Options APIのMixins、レンダープロップス、スコープ付きスロットなどのロジック再利用手法の良いところを取り入れ、さらにリアクティブシステムとの統合を深めた、Composition APIの中心的な設計パターンと言えます。大規模なアプリケーションで共通ロジックが多い場合、積極的にComposablesを活用することで、コードベースを効率的かつメンテナンスしやすく保つことができます。

7. Options APIとの比較と共存

Composition APIはOptions APIを完全に置き換えるものではありません。両方のスタイルはVue 3でサポートされており、同じプロジェクト内、さらには同じコンポーネント内で共存させることも可能です。

Options API と Composition API の比較:

特徴 Options API Composition API
記述スタイル オプション(data, methodsなど)ごとに分類 機能ごと(ロジックグループ)に setup 関数内で記述
ロジック整理 機能が複数のオプションに分散しがち 関連ロジックをまとめて記述しやすい
ロジック再利用 Mixins (課題あり), Renderless Components, etc. Composables (シンプルで強力、名前衝突なし、型推論◎)
可読性 小規模コンポーネントでは分かりやすい 大規模コンポーネントで関連ロジックを探しやすい。Composablesによる分離も効果的。
TypeScript 型推論が難しい場合がある 型推論との相性が良い
学習曲線 初心者には直感的で学びやすい リアクティブAPI (ref, reactive) の理解が必要。関数の概念に慣れていると有利。
バンドルサイズ 小規模なOptions APIコードは少し有利な場合も Shimなどが必要なく、Options APIよりわずかに有利な場合がある

どちらを選ぶべきか?

  • Options API:

    • 小〜中規模で、ロジックが比較的単純なコンポーネント。
    • Vueの学習を始めたばかりで、基本的な概念に慣れたい場合。
    • 既存のOptions APIプロジェクトに追加機能を開発する場合。
  • Composition API:

    • 大規模で複雑なコンポーネント。
    • コンポーネント間で共通のロジックを頻繁に再利用する場合。
    • TypeScriptを活用して堅牢なアプリケーションを開発したい場合。
    • リアクティブシステムとより密接に連携するロジックを記述する場合。

多くのプロジェクトでは、これらのスタイルを組み合わせて使用することになるでしょう。例えば、基本的なコンポーネントはOptions APIで記述し、特定の複雑な機能や再利用したいロジックを持つコンポーネントはComposition APIで記述する、といった具合です。

Options API と Composition API の共存:

同じコンポーネント内で Options API と Composition API (setup 関数) を両方記述することも可能です。この場合、以下のルールが適用されます。

  • setup 関数は、Options API の beforeCreatecreated フックよりも前に実行されます。
  • setup 関数から返されたプロパティは、Options API のプロパティ(data, methods, computed など)の前にコンポーネントインスタンスに注入されます。
  • もし setup から返されるプロパティの名前が Options API のプロパティ名と衝突した場合、setup から返されるプロパティが優先されます

“`vue

“`

共存時の注意点:

  • setup 関数内からは、Options API で定義されたプロパティ (data, methods, computed など) には this 経由で直接アクセスできません。(これは、setup が Options API のオプションが処理される前に実行されるためです。)
  • Options API のプロパティは、setup 関数から返されたプロパティやメソッドに this 経由でアクセスできます。ただし、これは非推奨のパターンです。可能な限り、コンポーネントのロジックはどちらか一方のスタイルに統一するか、setup 関数内でOptions APIのメソッドをラップして呼び出すなど、明確な依存関係になるように記述することが望ましいです。
  • 基本的に、共存させる場合は setup 関数で Composition API のロジックを記述し、Options API は最小限にするか、新しいコンポーネントでは Composition API に統一するのが良いでしょう。最もクリーンなのは、完全にどちらかのスタイルに統一することです。

新しいプロジェクトで Composition API を採用する場合、Options API との共存は既存コードからの移行時や、一部のライブラリとの連携が必要な場合に限られることが多いでしょう。

8. TypeScriptとの連携

Composition APIは、TypeScriptとの相性が非常に優れています。関数ベースの記述スタイルと、ref, reactive, computed といった型推論しやすいAPI設計により、より堅牢で保守性の高いコードをTypeScriptで記述できます。

基本的な型付け:

  • ref:
    ref を使う場合、初期値から型が自動的に推論されます。明示的に型を指定したい場合は、ジェネリクスを使用します。
    “`typescript
    import { ref, Ref } from ‘vue’;

    const count = ref(0); // 型は Ref と推論される
    const name = ref(‘Vue’); // 型は Ref と推論される
    const isActive = ref(true); // 型は Ref と推論される

    // 明示的に型を指定
    const userId: Ref = ref(null); // null または number 型の ref
    const items: Ref = ref([]); // 文字列配列型の ref

    userId.value = 123; // OK
    // userId.value = ‘abc’; // TypeScriptエラー
    “`

  • reactive:
    reactive を使う場合、引数のオブジェクトから型が自動的に推論されます。オブジェクトの型を明示的に指定したい場合は、インターフェースやタイプエイリアスを使用します。
    “`typescript
    import { reactive, Reactive } from ‘vue’;

    interface User {
    id: number;
    name: string;
    isActive: boolean;
    roles: string[];
    }

    const user = reactive({
    id: 1,
    name: ‘Alice’,
    isActive: true,
    roles: [‘admin’, ‘editor’]
    });
    // 型は Reactive と推論される

    // 明示的に型を指定
    const anotherUser: Reactive = reactive({
    id: 2,
    name: ‘Bob’,
    isActive: false,
    roles: [‘viewer’]
    });

    user.name = ‘Alice Smith’; // OK
    // user.id = ‘abc’; // TypeScriptエラー
    // user.email = ‘[email protected]’; // TypeScriptエラー(Userインターフェースにemailがない)
    “`

  • computed:
    computed のゲッター関数から戻り値の型が自動的に推論されます。明示的に型を指定することも可能です。
    “`typescript
    import { ref, computed, ComputedRef } from ‘vue’;

    const count = ref(0);
    const message = ref(‘count: ‘);

    const display = computed(() => message.value + count.value);
    // 型は ComputedRef と推論される

    // 明示的に型を指定
    const isEven: ComputedRef = computed(() => count.value % 2 === 0);
    “`

  • props:
    setup 関数の props 引数は、コンポーネントの props オプションの定義に基づいて型が自動的に推論されます。defineProps マクロ(<script setup> でよく使われる)を使用すると、より強力な型推論が得られます。
    typescript
    // Options API スタイルの props 定義 + Composition API
    export default {
    props: {
    message: {
    type: String,
    required: true
    },
    count: Number
    },
    setup(props) {
    // props の型は { message: string, count?: number } のように推論される
    console.log(props.message.toUpperCase()); // OK
    // console.log(props.count.toFixed(2)); // count が undefined の可能性があるのでエラーになる場合がある
    // 型ガードやオプショナルチェーンを使う
    if (props.count !== undefined) {
    console.log(props.count.toFixed(2));
    }
    }
    }

    <script setup> を使うと、defineProps に型引数を与えることでより簡単に型定義できます。

    “`typescript
    //
    ``


    ``
    このように Composable 関数に型引数を渡すことで、
    dataref の型がRefと推論され、テンプレート内やスクリプトブロック内でdata.value` にアクセスする際に型の恩恵を受けられます。

    Composition API は関数ベースで明確な入出力を持つため、TypeScriptとの連携が非常に自然です。大規模なプロジェクトでTypeScriptを採用している場合、Composition APIは開発体験とコードの保守性を大きく向上させる強力なツールとなります。

    9. 高度なトピック:Provide/Inject, テンプレート参照, <script setup>

    Composition APIは、基本的な状態管理やウォッチャーだけでなく、Options APIで提供されていた他の機能にも対応するAPIを提供しています。また、開発効率をさらに向上させるための <script setup> 構文も導入されました。

    Provide / Inject (provide, inject)

    コンポーネントツリーの深い階層にある子孫コンポーネントにデータを渡したい場合、Props をバケツリレーのように渡していくのは煩雑になります。Vueでは、このような場合に provide / inject という機能を使用します。親コンポーネントが provide でデータを提供し、子孫コンポーネントが inject でそのデータを受け取ります。

    Composition APIでは、provide および inject 関数が提供されています。

    ```vue

    ```

    ```vue

    ```

    ```vue

    ``inject関数の第2引数には、提供された値が存在しなかった場合のデフォルト値を指定できます。また、Vue 3.3 以降では、第2引数にオプションオブジェクトを渡すことでrequired: true` を指定し、必須の依存関係として存在しない場合に警告を出すようにできます。

    Provide/Inject は、主にプラグインの開発や、アプリケーション全体で共有される設定値や状態(例: テーマ、ロケール、認証情報)をコンポーネントツリーの下流に伝える場合に使用されます。ただし、親から子への明示的な依存関係を隠蔽するため、多用しすぎるとコンポーネント間の関係が分かりにくくなる可能性がある点には注意が必要です。グローバルな状態管理には Vuex や Pinia のようなライブラリを使用する方が適切な場合が多いです。

    テンプレート参照 (ref)

    特定のDOM要素や子コンポーネントインスタンスに直接アクセスしたい場合、Options APIでは ref 属性と this.$refs を使用しました。Composition APIでも同様に ref を使用しますが、こちらはリアクティブなテンプレート参照を管理する ref 関数を利用します。

    1. ref を使用してテンプレート参照を作成: setup 関数内で ref 関数を呼び出し、初期値 null を指定してテンプレート参照用のリアクティブな参照を作成します。
    2. テンプレートで ref をバインド: テンプレート内で、アクセスしたい要素に ref 属性を付与し、作成したテンプレート参照の名前を文字列で指定します。(例: <input ref="myInput">
      <script setup> 構文を使用する場合は、テンプレート参照用のリアクティブな参照の名前を直接 ref 属性の値として指定します。(例: <input :ref="myInputRef"><script setup> では ref="myInputRef" のように文字列指定でも動作しますが、テンプレート参照の変数名を直接バインドする方が一般的です。)
    3. onMounted でアクセス: コンポーネントがDOMにマウントされた後、onMounted フック内でテンプレート参照の .value プロパティを通じて実際のDOM要素やコンポーネントインスタンスにアクセスします。

    ```vue

    ``
    テンプレート参照の
    .valueは、コンポーネントがマウントされるまではnullです。そのため、.valueを介してDOM操作などを行う場合は、onMounted` フック内で行うことが一般的です。

    子コンポーネントのインスタンスへの参照を取得した場合、そのインスタンスが <script setup> を使用している場合、デフォルトでは Composition API の内部状態や関数は公開されません。明示的に公開するには、子コンポーネントの <script setup> 内で defineExpose マクロを使用する必要があります。

    ```vue

    ```

    <script setup>

    <script setup> は、Vue 3.2 で導入された、Composition API をより簡潔に記述するための構文シュガーです。コンポーネントの単一ファイルコンポーネント(SFC)内で使用されます。

    <script setup> を使用すると、setup 関数を明示的に定義する必要がなくなります。トップレベルで宣言された変数やインポートは、自動的にテンプレートに公開され、コンポーネントインスタンスの一部として利用可能になります。

    ```vue


    ``
    **

    ``
    この例では、
    refで状態、computedで算出プロパティ、関数でメソッドを定義し、watchで状態の変化を監視しています。

    ``onMountedフック内で非同期関数fetchDataを呼び出し、その中でfetchAPIを使ってデータを取得しています。loadingerrorの状態をref` で管理し、テンプレートでその状態に応じて表示を切り替えています。

    例3:フォーム入力処理とバリデーション

    フォームの入力値を ref で管理し、入力値の変化に応じて簡単なバリデーションを行う例です。

    ```vue

    ``
    この例では、
    v-modelで入力値とrefをバインディングし、watchを使って入力値の変更を監視し、リアルタイムにバリデーションエラーメッセージを更新しています。computed` でフォーム全体の有効性を判定し、送信ボタンの disabled 状態を制御しています。

    これらの例から分かるように、Composition API を使うと、関連する状態、算出プロパティ、メソッド、ウォッチャー、ライフサイクルフックを機能ごとにまとめて記述でき、コードの可読性と保守性が向上します。

    11. Composition APIを使う上でのベストプラクティス

    Composition APIを効果的に活用するためには、いくつかのベストプラクティスがあります。

    1. 関連ロジックはまとめて記述する: setup 関数内では、特定の機能に関連するリアクティブな状態、算出プロパティ、ウォッチャー、メソッドなどを可能な限りまとめて記述するように心がけます。これにより、コードが機能ごとに整理され、可読性が向上します。
    2. 複雑なロジックや再利用可能なロジックはComposablesとして切り出す: setup 関数が肥大化してきた場合や、複数のコンポーネントで同じロジックを使いたい場合は、そのロジックを Composable (useXXX 関数) として独立したファイルに切り出します。これにより、setup 関数がシンプルになり、コードの再利用性も高まります。
    3. refreactive の使い分けを明確にする:
      • 単一のプリミティブ値やオブジェクトを扱う場合は ref
      • 複数の関連するプロパティを持つ複雑なオブジェクトを扱う場合は reactivetoRefs の組み合わせ。
      • チーム内でどちらかに統一するルールを設けるのも良いでしょう(例: すべて ref で扱う、オブジェクトは reactive で扱うなど)。重要なのは一貫性です。
    4. watchwatchEffect を適切に使い分ける:
      • 特定の値を監視し、新旧の値にアクセスして副作用を実行する場合は watch
      • コールバック内で参照されるすべてのリアクティブな状態に反応して副作用を実行する場合は watchEffect
      • watchEffect は便利ですが、意図しない依存関係を追跡してしまう可能性もあるため、挙動を理解して使用します。
    5. ライフサイクルフックをクリーンアップに使用する: onMounted などで登録したイベントリスナー、タイマー、購読などは、忘れずに onUnmounted でクリーンアップします。非同期処理のキャンセルには watchEffectonInvalidate が役立ちます。
    6. TypeScriptを活用する: Composition APIはTypeScriptとの相性が良いので、積極的に型付けを行います。これにより、コードの堅牢性が高まり、開発時のエラーを減らすことができます。Composablesの引数や戻り値に型を定義すると、再利用時の開発体験が向上します。
    7. <script setup> を優先的に使用する: 新しいコンポーネントで Composition API を使用する場合は、<script setup> を使用することでコードが簡潔になり、開発効率が向上します。
    8. テンプレート参照は必要な場合にのみ使用する: DOM要素や子コンポーネントインスタンスへの直接アクセスは、Vueの宣言的なアプローチから外れるため、本当に必要な場合に限定して使用します。フォーム要素へのアクセスや、特定のライブラリとの連携などで使用することが多いです。
    9. Provide/Inject は広範囲な依存関係に使用する: コンポーネントツリーを深く伝搬させたい設定値やサービスなどに Provide/Inject を使用します。ローカルな状態管理やコンポーネント間の単純な親子関係には Props や Emit を使用します。
    10. 命名規則: Composable 関数には use 接頭辞をつけるという慣習に従うと、コードの意図が分かりやすくなります。リアクティブな変数名も分かりやすい名前をつけましょう。

    これらのベストプラクティスを意識することで、Composition API のメリットを最大限に引き出し、Vue.js アプリケーションを効率的かつメンテナンスしやすく開発することができます。

    12. まとめ:Composition APIはVue開発の未来をどう変えるか

    この記事では、Vue Composition APIについて、その導入背景、基本的なAPI、リアクティブ性の詳細、ウォッチャー、ライフサイクルフック、ロジック再利用のためのComposables、Options APIとの比較、TypeScriptとの連携、そして実践的なコード例とベストプラクティスを詳細に解説しました。

    Composition API は、特に大規模なアプリケーションや複雑なコンポーネントにおいて、Options API が抱えていた課題(関連ロジックの分散、ロジック再利用の困難さ、TypeScriptとの相性)を効果的に解決するための新しい記述スタイルを提供します。

    Composition APIの主な利点:

    • コードの整理: 機能ごとにロジックをまとめて記述できるため、コードの可読性と保守性が向上します。
    • 強力なロジック再利用: Composables パターンにより、コンポーネント間で複雑なロジックを簡単かつ安全に共有できます。
    • 優れたTypeScriptサポート: 型推論がしやすく、堅牢なコードを記述できます。
    • 柔軟性: Options API と組み合わせることも可能であり、既存プロジェクトへの段階的な導入も比較的容易です。

    Composition API はVue 3 の主要な機能の一つであり、Vue.js エコシステムの多くのライブラリやツールも Composition API に対応または最適化されています。(<script setup> はその代表例です。)

    Composition API を学ぶことは、Vue.js 開発者としてより高度なアプリケーション構築スキルを身につける上で非常に価値があります。最初は Options API との考え方の違いに戸惑うかもしれませんが、リアクティブな状態管理 (ref, reactive) やウォッチャー (watch, watchEffect)、そして Composables の概念を理解すれば、その強力さと柔軟性を実感できるはずです。

    どのようなプロジェクトでどの記述スタイルを選ぶかは開発者の判断に委ねられますが、特に長期的にメンテナンスが必要な大規模プロジェクトや、チーム開発を行う場合は、Composition API の採用を検討する価値は十分にあります。

    この記事が、あなたが Composition API を理解し、自身のVue.js 開発に取り入れるための一助となれば幸いです。 Composition API をマスターして、さらに効率的で高品質なVue.js アプリケーション開発を目指しましょう!

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

上部へスクロール