propsに関数を渡すのは Vue.js のアンチパターンである


スポンサーリンク

Reactでは、親コンポーネントから子コンポーネントへ、関数をプロップとして渡すことができます。

関数の呼び出しは、子から親へと逆流し、親子のコンポーネントのコミュニケーションを促進します。

これは、Vue.jsでも次のようなコードで実現できます。

<template>
  <Child :callback="doSomething" />
</template>

<script>
  export default {
    name: 'Parent',

    methods: {
      doSomething() {
        //
      }
    }
  }
</script>

そして、子コンポーネントでは、関数をpropとして受け取ります。

<template>
  <a @click="execute">Execute action</a>
</template>

<script>
  export default {
    props: {
      callback: {
        type: Function
      }
    },

    methods: {
      execute() {
        // ... do something here

        if (this.callback) {
          this.callback()
        }
      }
    }
  }
</script>

Vue.js ではカスタムイベントを使う

上の例は完璧に動作しますが、Vueではほとんどの場合、アンチパターンとみなされます。

関数をpropとして渡すことで、親と子の両方のコンポーネントを双方向のデータバインディングでリンクしています。

上の例では、子コンポーネントは親コンポーネントの関数propのコンテキストを知る必要があります。実行するたびに、渡されたコールバック関数をチェックして実行する必要があります。

この子コンポーネントを再利用すると、異なる親から渡された異なるコールバック関数を持つようになります。

アプリケーションのサイズが大きくなり、他の開発者が参加するようになると、子コンポーネントのコードを見て、どのコールバック関数のプロップなのか、それがどこから来たのかを理解しなければなりません。

その代わり、Vue.jsには、同じことを実現するカスタムイベントシステムがあります。

# Parent
<template>
  <Cat @onHappy="doSomething" />
</template>

<script>
  export default {
    name: 'Parent',

    methods: {
      doSomething() {
        //
      }
    }
  }
</script>

# Child Cat component
<script>
  export default {
    methods: {
      eats() {
        this.$emit('onHappy')
      }
    }
  }
</script>

Catコンポーネントのeatsメソッドが呼び出されるたびに、onHappyイベントが発行されます。

親はonHappyイベントを待ち、対応する関数を呼び出すことができます。データの流れは一方向だけなので、デバッグも非常に楽になります。

関数を prop として渡すことの利点は、コードがよりクリーンでDRYになることです。

イベントを発生させてそれを待つのではなく、関数を渡してそれを子コンポーネントから呼び出すことができます。

ほとんどの場合、これは良いアイデアではありませんが、2つのコンポーネントがどのような場合でも結合されなければならず、子コンポーネントが他のシナリオで再利用されない場合は、この方法を検討すると良いでしょう。

とはいえ、ほとんどの場合、イベントはメインのアプローチであるべきで、これは最大限の注意を払って使用するべきです。