Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

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

More than 3 years have passed since last update.

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時間ぐらいハマっていました。。。
ドキュメントに書いてあるのですが、完全に見落としていました。

参考サイト

_Keitaro_
2015.12からWEB制作会社で、主にWEBシステム開発の仕事をしています。
karabiner
主にシステム開発・アプリ開発・ Webサイト制作を行う会社です
http://www.karabiner.tech/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away