このような疑問をお持ちの方に向けて書いています。
- 親コンポーネントから子コンポーネントへの値はpropsで渡す
- 子コンポーネントから親コンポーネントへ値は$emitを使える
- 規模が大きめのシステムの場合は値を渡す時はVuexを使う
この記事では上記の内容を知ることができます。初学者向けの内容となっています。
Vue.jsは日本ではReactと並ぶ人気のJavaScriptフレームワーク。2020年も人気上昇中ですね。そろそろjQueryを卒業してVue.jsを始めましょう。では本題に入っていきます。
Vue.jsのコンポーネントについて
コンポーネントは部品という意味で、コンポーネント化しておくことで、その部品を使いたい場所でimportして使えるみたいなものですね。
一番上のコンポーネントが、いろんな部品をimportして一つの画面を構成しています。
親コンポーネントから子コンポーネントに値を渡したり、さらに孫コンポーネントに値を渡したり。また、逆もあり孫から別の孫に渡す必要があったりします。
そうすると普通に孫→子→親、そして別の子→孫みたいなことをすると複雑になってしまうわけです。
この後は実際に値の受け渡しについて記述していきます。
親から子へのデータの受け渡しはprops
親コンポーネントから子コンポーネントの値の受け渡しについて説明します。
以下はサンプルコード
App.vue
<template> <div id="app"> <Header msg="〇〇株式会社"/> </div> </template> <script> import Header from './components/Header.vue' export default { name: 'App', components: { Header } } </script> <style> #app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>
Header.vue
<template> <div> {{ msg }} </div> </template> <script> export default { name: 'Header', props: ['msg'] } </script> <style scoped> </style>
子コンポーネントで値を受け取るにはpropsを使う
上のソースコードで親はApp.vueで子がHeader.vueになります。App.vueにHeader.vueをimportしてます。以下の部分で子のコンポーネントにmsgという名前で値を渡しています。
<Header msg="〇〇株式会社"/>
子のコンポーネントの方は「props」というプロパティを使い、配列(オブジェクトでも可能)でなっていてmsgという名前で値を受け取ることができます。
props: ['msg']
めちゃくちゃシンプルな画面ができましたヽ(´ー`)ノ
propsではバリデーションも書ける
propsでは配列ではなく、オブジェクトでも書けます。以下のような感じ。msgにStringという型を設定しています。型が違うとエラーになります。
props: { msg: String }
さらにmsgもオブジェクトにして以下のように書くことも可能。親のmsgを消すと子の方ではdefaultの'ようこそ'が表示されるようになります。
props: { msg: { type: String, default: 'ようこそ' } }
子から親へのデータの受け渡し
子から親にデータを渡す方法はいくつかあるので、紹介していきます。ちょっとつまらないサンプルコードを準備しました。
横線の上の方が子コンポーネント、下が親コンポーネントです。子コンポーネントの「+ 1」ボタンをクリックすると親に値が渡り、それを表示しています。
App.vue
<template> <div id="app"> <Header v-on:count-up="parent = $event" /> <hr /> <p>犬は{{ parent }}匹飼っています。</p> </div> </template> <script> import Header from './components/Header.vue' export default { name: 'App', components: { Header }, data() { return { parent: 0 } } } </script> <style> #app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>
Header.vue
<template> <div> <p>犬は何匹飼っていますか?</p> <p><button @click="countUp"> + 1 </button></p> </div> </template> <script> export default { name: 'Header', data() { return { children: 0 } }, methods: { countUp() { this.$emit('count-up', this.children += 1) } } } </script>
子コンポーネントで親に値を渡す時には$emitが使える
子コンポーネントにある「 + 1 」ボタンをクリックするとcountUpメソッドが呼ばれ、$emitを使い現在の値に+1して、count-upという名前で親に渡しています。
親はv-on:count-up="parent = $event"で値を受け取っています。
ちょっと面倒ですね。
$emitは子から親のイベントを発火させるために使える
$emitは値を渡さなくても親のメソッドのイベント発火用にも使える。
App.vue
<template> <div id="app"> <Header v-on:count-up="countUp()" /> <hr /> <p>犬は{{ parent }}匹飼っています。</p> </div> </template> <script> import Header from './components/Header.vue' export default { name: 'App', components: { Header }, data() { return { parent: 0 } }, methods: { countUp() { return this.parent++ } } } </script> <style> #app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>
Header.vue
<template> <div> <p>犬は何匹飼っていますか?</p> <p><button @click="countUp"> + 1 </button></p> <!-- {{ count }} --> </div> </template> <script> export default { name: 'Header', data() { return { children: 0 } }, methods: { countUp() { this.$emit('count-up') } } } </script>
最初に書いたサンプルソースの以下の部分では$emit()に二つの引数を渡していました。けれども今回のサンプルソースでは引数が一つで値は渡していない。
this.$emit('count-up', this.children += 1)
親コンポーネントの以下の部分ではcountUp()メソッドが呼ばれてカウントアップしている。
<Header v-on:count-up="countUp()" />
ただ単に親のメソッドを子が発火させるという使い方もできる例でした。
子から親に値を渡す場合は、$emitよりもvuexというものを使う方が一般的で、そちらの使い方も別途書いていこうかなと思います。
まとめ
上では$emitを使い親に値を渡すということをしていました。小さいプロジェクトで子から親だけの場合は、$emitを使うということもありかもですが、子から親、さらに別の子へデータを渡すという場合もあります。
子から親に$emitして親から別の子にpropsで渡してみたいなことをしなければならない。そんな時には一般的にはVuexを使う方がよいとされています。
Vuexを使うと子と子でデータの共有ができたりするため、多くのプロジェクトはVuexを使っています。Vuexについては別記事で紹介しようと思います。