そんな中、なぜか親コンポーネントから子コンポーネントにデータを渡すことができずハマりかけたので共有する。
ちなみにvue-cliを使っているので、次のようなディレクトリ構成になっている。
. ├── src │ ├── App.vue │ ├── assets │ │ ├── icon.png │ ├── components │ │ ├── Card.vue │ │ └── TimeLine.vue │ └── main.js └── static └── data.json
vue-cliの使い方は、次の記事を参考にしてほしい。
親コンポーネントから子コンポーネントにデータを渡す
Compotentsの関係は、App.vue > TimeLine.vue > Card.vueとしている。
App.vueでdata.jsonを読み込み、そのデータをTimeLine.vueを経由して、Card.vueまで渡す方法を例にまとめる。
App.vue → TimeLine.vueは、普通にdataで定義した値をpropsで受け取る。
TimeLine.vue → Card.vueは、v-forでループさせたときの値を渡す。
// data.json
{
"timelines": [
{
"date": "2016/10/07",
"event": "できごと1"
},
{
"date": "2016/10/08",
"event": "できごと2"
},
(以下略)
]
}
<!-- App.vue -->
<template>
<time-line :timelines="timelines"></time-line>
</template>
<script>
import TimeLine from './components/TimeLine'
import data from '../static/data.json'
export default {
components: {
TimeLine
},
data () {
return {
timelines: data.timelines
}
}
}
</script>
<!-- TimeLine.vue -->
<template>
<div>
<ul>
<card v-for="tl in timelines" :timeline="tl"></card>
</ul>
</div>
</template>
<script>
import Card from './Card'
export default {
components: {
Card
},
props: ['timelines']
}
</script>
<!-- Card.vue -->
<template>
<li>{{timeline.date}} - {{timeline.event}}</li>
</template>
<script>
export default {
props: ['timeline']
}
</script>
propsだけでなくv-bindが必要
すべてのコンポーネントは別々のスコープを持っているので、子コンポーネントから親コンポーネントのデータを参照することができない。
そのため、データを渡すときも明示的に指定しなければならない。
もうちょっと簡単な例に置き換えてみる。
<!-- Parend.vue -->
<template>
<my-component v-bind:myMessage="parentData"></my-component>
</template>
<script>
import MyComponent from './components/MyComponent'
export default {
components: { MyComponents },
data: {
parentData: ['Alfa', 'Bravo', 'Charlie']
}
}
</script>
<!-- MyComponent.vue-->
<template>
<p>{{myMessage}}</p>
</template>
<script>
export default {
props: ['myMessage'],
created: () => {
console.log(this.myMessage)
}
}
</script>
このような関係の場合について説明する。
親コンポーネントで、すること
親コンポーネントから子コンポーネントにデータを渡す場合は、カスタムディレクティブ(ここではmy-component)のところに「v-bind:<渡すときの変数名>="<自身のデータ>"」と明示的に指定しなければならない。ちなみにv-bind:myMessageは:myMessageと省略することができる
<渡すときの変数名>は、子コンポーネントのpropsで指定する名前。
<自身のデータ>は、new Vue(ここではexport defaultのところ)で指定したdataのデータ(この場合はparentData)を指定する。
子コンポーネントで、すること
親コンポーネントからデータを受け取る場合は、propsに親から渡ってくる変数名を書く(ここではmyMessage)
各メソッドでは、this.myMessageの要領でアクセスできる。
追記: 2016/10/11 11:30
Twitterで以下のような指摘をされた。
Vue.js2.x系で親から子コンポーネントにデータを渡す方法|Black Everyday Company @bc_rikkoさんから https://t.co/5lf7SRvhfh— z@kuro (@zakuro9715) 2016年10月11日
微妙に正しくない。v-bind と props の話が混ざってしまっている。
ということで、実際にためしてみた。まとめ— z@kuro (@zakuro9715) 2016年10月11日
- props に指定するだけで、値を受け取る事ができる。
- 属性の値は式ではないので、変数名を指定しても変数は使えない
- v-bind を使うことで、擬似的に属性の値に式が使えるようになる。
すべてのコンポーネントは別々のスコープを持っているので、子コンポーネントから親コンポーネントのデータを参照することができない。
そのため、データを渡すときも明示的に指定しなければならない。
の部分がちょっと違う。正しくは以下のとおり。
- 静的な値は、propsに指定するだけで値を受け取ることができる(Components#Passing Data with Props)
- 動的な値は、v-bindを使って式として評価することで、値を受け取ることができる(Components#Dynamic Props)
さいごに
公式ドキュメントをざっと流し読みしただけで、「props」さえ指定していればデータが受け取れると思っていた。
また、公式ドキュメントのpropsでは、子コンポーネントのサンプルしか載ってなく、親コンポーネントでどうすればいいのかわからず、かなり悩んだ。
この記事が、同じようにハマった人の参考になればと思う。
追記: 2016/10/26 10:00
Vue.js 2.x系で親子コンポーネント間のデータのやりとりについて、サンプルコードと図解を交えて解説している。
参考サイト
余談だが、ちょっと前にjp.vuejs.orgにコントリビュートした。(vuejs/jp.vuejs.org#125)
中の方たちは日本人で、安心して日本語でPullRequestを送ることができる。
気づいた点があったらぜひPullRequestを送ってみて欲しい!
以上
written by @bc_rikko
とても参考になりました。
返信削除が、App.vue のサンプル内にて、
<scritp> になっていてコピペで動きませんでした・・・。
<script> ですね。(tp→pt)
あえての罠?まったく気付かずにハマりました(汗)
お陰で、理解は深まりました!
コメント&ご指摘ありがとうございます!
削除ああああお恥ずかしい。
さっそく修正いたしました。
この部分でハマっていたのでとても助かりました!ありがとうございます。
返信削除コメントありがとうございます!
削除お役にたててなによりです。