10.

Vue.js メソッド定義完全ガイド(Options API / Composition API / setup)

編集
この記事の要点
  • Options API: methods: { greet() { ... } } に並べる。this でデータにアクセス可
  • Composition API + <script setup>: const greet = () => { ... } として宣言、this 不要
  • テンプレートからの呼出: @click="greet" / 引数付き: @click="greet('hello')" / イベントオブジェクト: @click="greet($event)"
  • computed と methods の違い: computed はキャッシュされる / methods は毎回実行
  • 子→親通信は emit('custom-event', payload)defineEmits で型定義

Vue.js のメソッド定義 2 つのスタイル

Vue.js 3 では「Options API」と「Composition API」の 2 つの書き方があり、メソッド定義もそれぞれスタイルが異なります。

1. Options API でのメソッド定義

<!-- src/components/Greeting.vue -->
<template>
  <div>
    <p>{{ message }}</p>
    <button @click="greet">挨拶する</button>
    <button @click="greetTo('世界')">世界に挨拶</button>
    <input @input="updateMessage" :value="message">
  </div>
</template>

<script>
export default {
  data() {
    return {
      message: 'こんにちは',
    };
  },
  methods: {
    greet() {
      // this でデータと他メソッドにアクセス
      this.message = 'やあ!';
      this.logIt();
    },
    greetTo(name) {
      this.message = `${name}、こんにちは!`;
    },
    updateMessage(event) {
      this.message = event.target.value;
    },
    logIt() {
      console.log('logged:', this.message);
    },
  },
};
</script>

Options API のポイント

  • すべてのメソッドは methods: オブジェクト内に並べる
  • メソッド内では thisdata / props / 他メソッド / computed にアクセス
  • アロー関数で書いてはいけないthis が外側の this になってしまう)
  • 非同期処理 (async/await) もそのまま使える

2. Composition API + <script setup>

<!-- src/components/Greeting.vue (Composition API) -->
<template>
  <div>
    <p>{{ message }}</p>
    <button @click="greet">挨拶する</button>
    <button @click="greetTo('世界')">世界に挨拶</button>
    <input @input="updateMessage" :value="message">
  </div>
</template>

<script setup>
import { ref } from 'vue';

const message = ref('こんにちは');

// アロー関数 or 通常 function どちらでも OK
const greet = () => {
  message.value = 'やあ!';
  logIt();
};

function greetTo(name) {
  message.value = `${name}、こんにちは!`;
}

const updateMessage = (event) => {
  message.value = event.target.value;
};

const logIt = () => {
  console.log('logged:', message.value);
};
</script>

Composition API のポイント

  • メソッドは通常の関数として <script setup> 内で宣言
  • this存在しない(不要)
  • ref/reactive の値には .value でアクセス(テンプレートでは自動アンラップ)
  • 外部公開(テンプレートから使える)は宣言するだけで自動
  • TypeScript との相性がよい

Options API vs Composition API 早見表

項目Options APIComposition API + setup
メソッド宣言methods: { greet() {} }const greet = () => {}
データ参照this.countcount.value
thisあり(コンテキスト)なし
アロー関数NG(this が変わる)OK
外部公開methods 内に書くだけ宣言するだけ
TS 補完限定的強力
ロジックの再利用mixin(推奨されない)composables(推奨)
学習コスト

テンプレートからの呼び出し方

<template>
  <!-- 引数なし: 関数参照を渡す -->
  <button @click="greet">A</button>
  <button v-on:click="greet">A(v-on の正式形)</button>

  <!-- 引数あり: 呼び出し式 -->
  <button @click="greet('hello')">B</button>

  <!-- イベントオブジェクトを渡す -->
  <input @input="handleInput($event)">

  <!-- 引数 + イベント両方 -->
  <button @click="handleClick('foo', $event)">C</button>

  <!-- 修飾子 (.prevent, .stop, .once, .capture, .self) -->
  <form @submit.prevent="onSubmit">...</form>
  <a @click.stop="onClick">伝播止める</a>

  <!-- キー修飾子 -->
  <input @keyup.enter="onEnter">
  <input @keyup.esc="onCancel">

  <!-- ボタン修飾子 -->
  <div @click.right="onRightClick">右クリック</div>
</template>

computed と methods と watch の違い

用途methodscomputedwatch
計算結果を表示毎回再実行★ キャッシュされる
クリック等のイベント処理★ これが本職
値が変わったときに副作用実行★ これが本職
引数を受ける○(が再評価されない)
非同期処理×(同期のみ)
<script setup>
import { ref, computed, watch } from 'vue';

const count = ref(0);

// methods(呼び出すたびに実行)
const formatted = () => `現在: ${count.value}`;

// computed(依存値が変わったときだけ再計算、結果はキャッシュ)
const doubled = computed(() => count.value * 2);

// watch(変化に応じて副作用)
watch(count, (newVal, oldVal) => {
  console.log(`変化: ${oldVal} → ${newVal}`);
  localStorage.setItem('count', String(newVal));
});
</script>

<template>
  <p>{{ formatted() }}</p>   <!-- 関数呼び出し(毎回実行) -->
  <p>{{ doubled }}</p>        <!-- 値として参照(キャッシュ) -->
</template>

子→親通信: emit

<!-- 子コンポーネント Child.vue -->
<script setup>
// イベント名と型を宣言
const emit = defineEmits(['change', 'submit']);

const onClick = () => {
  emit('change', { id: 1, name: 'foo' });   // 親に値を渡す
};
</script>

<template>
  <button @click="onClick">送信</button>
</template>


<!-- 親 Parent.vue -->
<script setup>
import Child from './Child.vue';

const onChange = (payload) => {
  console.log('子から:', payload);
};
</script>

<template>
  <Child @change="onChange" />
</template>

ライフサイクルとメソッドの組合せ

<script setup>
import { ref, onMounted, onUnmounted } from 'vue';

const users = ref([]);
const intervalId = ref(null);

const fetchUsers = async () => {
  const res = await fetch('/api/users');
  users.value = await res.json();
};

onMounted(() => {
  // 初期ロード
  fetchUsers();
  // 30秒ごとに更新
  intervalId.value = setInterval(fetchUsers, 30000);
});

onUnmounted(() => {
  // アンマウント時にタイマー解除
  clearInterval(intervalId.value);
});
</script>
Options APIComposition APIタイミング
beforeCreatesetup() 直前インスタンス作成前
createdsetup()インスタンス作成済 / DOM 前
beforeMountonBeforeMountDOM 挿入直前
mountedonMountedDOM 挿入後(API 呼出はここ)
beforeUpdateonBeforeUpdate再レンダリング前
updatedonUpdated再レンダリング後
beforeUnmountonBeforeUnmount破棄直前
unmountedonUnmounted破棄完了

composables(ロジックの再利用)

Composition API の真価。メソッド + 状態をまとめて切り出し、他のコンポーネントで再利用できます:

// composables/useCounter.js
import { ref, computed } from 'vue';

export function useCounter(initial = 0) {
  const count = ref(initial);

  const increment = () => count.value++;
  const decrement = () => count.value--;
  const reset = () => count.value = initial;

  const isZero = computed(() => count.value === 0);
  const doubled = computed(() => count.value * 2);

  return { count, increment, decrement, reset, isZero, doubled };
}
<!-- 任意のコンポーネントで使用 -->
<script setup>
import { useCounter } from '@/composables/useCounter';

const { count, increment, decrement, reset, doubled } = useCounter(10);
</script>

<template>
  <p>カウント: {{ count }}(2 倍: {{ doubled }})</p>
  <button @click="increment">+</button>
  <button @click="decrement">-</button>
  <button @click="reset">リセット</button>
</template>

FAQ

Q: Options API と Composition API はどちらを使うべき?
A: 公式は新規プロジェクトでは Composition API を推奨。ただし Options API も将来も使えます。チームに合わせて選択。

Q: this がうまく動かない
A: Options API の methods 内でアロー関数を使っていないか確認してください。methods: { greet: () => { this.x } } は NG。methods: { greet() { this.x } } が正しい。

Q: @click="greet"@click="greet()" の違い
A: 前者は関数参照を渡す(イベントオブジェクトが第一引数に入る)、後者はその場で呼び出して戻り値を渡す。引数を渡したいときだけ括弧を付けます。

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. インストール(ファイルのダウンロード)
  2. npmを使用したプロジェクトの作成
  3. for 繰り返し処理
  4. ifの条件分岐とtemplateを用いたグループ化
  5. クリック時のイベント処理(on:click)
  6. modelとdata フォーム入力値とDOMへの即時反映
  7. computed(算出プロパティ)と使い方とdataとの違い
  8. ライフサイクルフック(created / mounted / updated / destroyedの使い方)
  9. $nextTickの使い方(ライフサイクルフック)
  10. メソッドの定義方法
  11. エラー一覧
  12. ルーティング設定
  13. aリンクの貼り方と動的URLの作成
  14. Mixinを利用した共通処理の記述方法
  15. v-bindによるデータ連携
  16. ヘッダー/フッターの共通コンポーネント
  17. ナビゲーションの現在ページをハイライトする方法
  18. 画面サイズの取得方法

最近更新/作成されたページ