137
115

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【Vue.js】propsで子コンポーネントにデータが渡らないのはHTMLの命名規則が原因だった

Last updated at Posted at 2018-02-11

propsを利用して親コンポーネントのデータを受け取ろうとしたが、そのデータがundefinedになり、
ハマったので、その備忘録です。

###親子間のデータ受け渡しについておさらい

まずはコンポーネントにおけるデータの流れについて少しおさらいしようと思います。

Vueでは、親子のコンポーネントの関係は、props down, events upというように要約することができます。
親は、 プロパティを経由して、データを子に伝え、子はイベントを経由して、親にメッセージを送ります。

props-events.png

####プロパティによるデータの伝達について

全てのコンポーネントインスタンスは、各自の隔離されたスコープ (isolated scope) を持ちます。
つまり、子コンポーネントのテンプレートで親データを直接参照できない(そしてすべきでない)ということです。
データはプロパティを使用して子コンポーネントに伝達できます。

要するに、すべてのコンポーネントは別々のスコープを持っているので、
子コンポーネントから親コンポーネントのデータを参照することはできないということです。

そのため、データを隔離されたスコープで子コンポーネントに渡すためには、propsオプションを利用する必要があります。

###propsオプションについて

親コンポーネントが持っているデータを子のコンポーネントに受け渡す役割を持ちます。
propsオプションを使って親のデータを受け取るには以下のルールがあります。

####ルールその1
親コンポーネントからデータを受け取るためのプロパティをpropsに書かなくてはなりません。
propsオプションを使うことで、子のコンポーネントはその属性で親のデータを受け取り、そのデータを使えるようになります。

親コンポーネント
new Vue({
	el: '#app',
	data: function() {
		return {
			myMessage: '親が持つメッセージデータ',
		}
	}
});
子コンポーネント
Vue.component('child-component', {
	props: ['myMessage'],// プロパティを記述
	template: '<span>{{myMessage}}</span>'
})

propsで宣言をしないと、コンポーネント内でそのデータはundefinedになってしまいます。

####ルールその2
propsに追加するだけでは、親から渡されたデータを利用することはできません。
明示的にテンプレートタグにデータをバインディングする必要があります。

HTML
<child-component v-bind:my-message="myMessage"></child-component>

先ほど、子のテンプレート内のpropsで記述したプロパティで、親のデータを受け取ります。

#####動的な値(非文字列テンプレート)について
静的な値(文字列テンプレート)をバインディングするケースは少なく、
上記の例のような動的な値をバインディングするケースの方が多いと思います。
その場合は、v-bindを使用することで属性の値に式が使えるようになります。
親のデータにプロパティを動的にバインディングすることで親でデータが更新される度に、
そのデータが子にも渡るようになります。

  • v-bindの省略記法を使用すると以下のようにシンプルに書けます。
HTML
<child-component :my-message="myMessage"></child-component>

#####プロパティ名について
別のデータに代入しているみたいな感じですが、親と子ではスコープが違うので
プロパティ名は親データと同じでも、下記のように別の名前を使っても大丈夫です。

親コンポーネント
new Vue({
	el: '#app',
	data: function() {
		return {
			myMessage: '親が持つメッセージデータ',
		}
	}
});
子コンポーネント
Vue.component('child-component', {
	props: ['message'],// プロパティを記述
	template: '<span>{{message}}</span>'
})
HTML
<child-component :message="myMessage"></child-component>

#####HTML内で動的な値(非文字列テンプレート)を使用する場合の注意点
HTMLの属性は大文字と小文字を区別しません。
そのため、動的な値(非文字列テンプレート)を使用する場合、
バインディングに利用するプロパティ名を属性として使用するときは、
それらをケバブケース (kebab-case: ハイフンで句切り) に変換して記述する必要があります。

キャメルケース:myMessage
ケバブケース:my-message

  • undefinedになる例
HTML
<child-component :myMessage="myMessage"></child-component>
  • ケバブケース
HTML
<child-component :my-message="myMessage"></child-component>

※静的な値(文字列テンプレート)を使用する場合は、この制限は適用されません。

JavaScriptではキャメルケースで書いていても、HTML内ではケバブケースの記法で書かないといけません。
自分はこれで1時間ぐらいハマっていました。。。
ドキュメントに書いてあるのですが、完全に見落としていました。

###参考サイト

137
115
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
137
115

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?