Ownedmedia ウェブ制作に役立つコンテンツを発信中!

Vue.js 2020.11.08

Vue.jsで親から孫まで多重階層になっているコンポーネント間で値を受け渡す

Tags: ,,

Vue.jsではコンポーネント間で値の受け渡しが行われることがあることを、過去にも「Vue.jsで$emitとv-onを使った子から親のコンポーネントにおける値の受け渡し」の記事や「propsで親コンポーネント内から子コンポーネントへ値やデータを渡す」でも紹介していましたが、今回は祖先コンポーネントから孫コンポーネントといった、多重階層の構成となっているコンポーネント間の値の受け渡しをしてみたいと思います。

 

基本的には親子コンポーネント間と同じ仕組みで、親から子への値の受け渡しは「props」で、子から親への値の受け渡しは、「$emit」で親要素のイベントをバインドさせて、それと合わせて値を入れる形になります。多重階層になることで複雑になる点に注意してみていきたいと思います。

 

propsで親(祖先)→子→孫へと値を受け渡す

まずは親から子のコンポーネント方向へ値を受け渡す場合です。こちらについては「props」を使って値を引き継ぐような形で、コンポーネント間における値の受け渡しの基本となり、とてもシンプルです。まずは親(祖先)コンポーネントを見ていきます。今回はテキストフィールドに入力した値を受け継ぐ想定で作成しています。「v-model」でコンポーネント内の「data」を更新し、そのデータを子コンポーネントにバインドしていきます。

【ParentComponent.vue】

<template lang="pug">
  div
    h1 親(祖先)コンポーネント
    label 親(祖先)コンポーネントから孫コンポーネントへ入力値を受け渡す:
      input(type="text" v-model="parentInputData")
    child-component(:parentToChild="parentInputData")
</template>

<script>
import ChildComponent from '~/components/ChildComponent.vue'
export default {
  name: 'ParentComponent',
  components: {
    ChildComponent
  },
  data() {
    return {
      parentInputData: ''
    }
  }
}
</script>

 

続いて子コンポーネントです。親コンポーネントからバインドされた値を「props」で受け取ります。そして受け取った値をそのまま孫コンポーネントにバインドさせていきます。子コンポーネントと同じ方法で値を引き継ぐことができます。

【ChildComponent.vue】

<template lang="pug">
  div
    h1 子コンポーネント
    grandchild-component(:childToGrandchild="parentToChild")
</template>

<script>
import GrandchildComponent from '~/components/GrandchildComponent.vue'
export default {
  name: 'ChildComponent',
  components: {
    GrandchildComponent
  },
  props: {
    parentToChild: {
      type: String,
      default: ''
    }
  }
}
</script>

 

最後に孫コンポーネントです。こちらも子コンポーネントと同じく、propsで送られてきた値を受け取り、それをテンプレート側に出力させることができます。下記ではcomputedを介していますが、そのままpropsの値を出力することもできます。

【GrandchildComponent.vue】

<template lang="pug">
  div
    h1 孫コンポーネント
    div 祖先コンポーネントから受け取った値:{{ grandchilOutputData }}
</template>

<script>
export default {
  name: 'GrandchildComponent',
  props: {
    childToGrandchild: {
      type: String,
      default: ''
    }
  },
  computed: {
    grandchilOutputData() {
      return this.childToGrandchild
    }
  }
}
</script>

 

実際にこれまでの流れを見ていくと、まず親コンポーネントで、dataの値が更新されています。

 

そして、子コンポーネントで引き継いだ値がpropsで受け取られていることが確認できますね。

 

最後に孫コンポーネントでも同じくpropsで受け取られている形になっています。

 

このように親から子コンポーネントへの値の受け渡しは多重階層のコンポーネントでも比較的シンプルでわかりやすいですね。

 

$emitで孫→子→親(祖先)へと値を受け渡す

続いて、先ほどとは逆に子コンポーネントから親コンポーネントへの値の受け渡しです。この場合には少しややこしく、親コンポーネント側で子コンポーネントのイベントをハンドリングし「$emit」を使ってイベントの発火と、値を指定することで、親コンポーネント側に値をイベントで実行した親コンポーネント側のメソッドの引数として受けとることができます。

 

まずは孫コンポーネントから見ていきます。ここでもテキストフィールドに入力した値を祖先コンポーネントまで受け渡していきます。v-modelでdataを更新し、その値を「$emit」の第二引数に指定し子コンポーネントに送ります。第一引数には孫コンポーネント用のイベントを定義します。このメソッドはテキストフィールドの値を更新したタイミングであるchangeイベントで実行します。

【GrandchildComponent.vue】

<template lang="pug">
  div
    h1 孫コンポーネント
    label 孫コンポーネントから祖先コンポーネントへ入力値を受け渡す:
      input(type="text" v-model="grandchildInputData" @change="grandchildEmit")
</template>

<script>
export default {
  name: 'GrandchildComponent',
  data() {
    return {
      grandchildInputData: ''
    }
  },
  methods: {
    grandchildEmit() {
      this.$emit('grandchild-event', this.grandchildInputData)
    }
  }
}
</script>

 

続いて子コンポーネントです。基本的に孫コンポーネントと同じで、親コンポーネントに値を送るために$emitを使って子コンポーネント用のイベント定義と受け取った値を入れていきます。これを子コンポーネントのメソッドとして、テンプレート側で孫コンポーネントのイベントで実行されるようにしておきます。

【ChildComponent.vue】

<template lang="pug">
  div
    h1 子コンポーネント
    grandchild-component(@grandchild-event="childMethod")
</template>

<script>
import GrandchildComponent from '~/components/GrandchildComponent.vue'
export default {
  name: 'ChildComponent',
  components: {
    GrandchildComponent
  },
  data() {
    return {
      grandchildToChild: ''
    }
  },
  computed: {
    childToParent() {
      return this.grandchildToChild
    }
  },
  methods: {
    childMethod(payload) {
      this.grandchildToChild = payload
      this.childEmit()
    },
    childEmit() {
      this.$emit('child-event', this.childToParent)
    }
  }
}
</script>

 

最後に親(祖先)コンポーネントです。ここでも同じ流れで子コンポーネントのイベントで、値を受け取るメソッドを実行することで、dataを更新しテンプレート側に値を出力することができます。

【ParentComponent.vue】

<template lang="pug">
  div
    h1 親(祖先)コンポーネント
    div 孫コンポーネントから受け取った値:{{ parentOutputData }}
    child-component(@child-event="parentMethod")
</template>

<script>
import ChildComponent from '~/components/ChildComponent.vue'
export default {
  name: 'ParentComponent',
  components: {
    ChildComponent
  },
  data() {
    return {
      parentOutputData: ''
    }
  },
  methods: {
    parentMethod(payload) {
      this.parentOutputData = payload
    }
  }
}
</script>

 

先ほどと同じく実際にこれまでの流れを見ていくと、まず孫コンポーネントで、dataの値が更新されています。

 

そして、子コンポーネントで孫コンポーネントのイベントによって値を受け取る子コンポーネントのメソッドが実行され、dataが更新されます。computedを介して、$emitにより親コンポーネントへ値が引き継がれていきます。

 

最後に親(祖先)コンポーネントでも同じく子コンポーネントのイベントによって値を受け取る形となります。

 

先ほどと比べても子コンポーネントから親コンポーネントへの値の受け渡しは、少し煩雑になるのでコードも増えてしまいます。なので、1階層くらいでは問題ないでしょうが、あまりに多重階層の場合にはVuexでstateとして値を管理する方が良さそうですね。

 


 

多重階層のコンポーネント間における値の受け渡しについては、基本的に親子コンポーネント間と同じ方法で繰り返していくだけですが、数が増えるほど管理がややこしくなりますので、stateでの状態管理の方法などと使い分けていくのがポイントになりそうですね。

 

(参考にさせて頂いたサイト)
Vue.js + Vuetify での親子孫コンポーネント間のデータ受け渡し(+ 考察)

この記事を書いた人

オガワ シンヤ

DesignSupply.代表 / ディレクター・ウェブデザイナー・フロントエンドエンジニアをやっています。「ウェブとデザインでヒト・モノ・サービスを繋げ新しい価値を生み出す」をコンセプトに日々奮闘中!制作中はチョコレートが欠かせない三十路Webクリエイター。

  • Twitter

コメントフォーム

記事に関するご質問やご意見などありましたら下記のコメントフォームよりお気軽に投稿ください。なおメールアドレスは公開されませんのでご安心ください。

内容に問題なければ、お名前・ハンドルネームとメールアドレスを入力いただき、下記の「コメントを送信」ボタンを押してください。

CAPTCHA


この記事もよく読まれています

Scroll to Top
ご質問・ご相談はありませんか ?