第12回 Vue.js入門 propsプロパティ 親から子へのデータの受け渡し

プログラミング
受け渡し

こんにちは、コンスキです。

前回は、Vue.jsのコンポーネントとはなにかという説明と、コンポーネントの作り方について説明しました。

今回は、2つのコンポーネント間での、データの受け渡し方について説明します。

データ受け渡しとは

データの受け渡しは、受け渡す方向によって受け渡し方は2種類に分かれます。

2種類のうち、今回は特に①のデータを親から子へ受け渡すために使うpropsプロパティについて詳しく説明します。

propsプロパティの説明には前置きがいくつもありますので、前置きはすでに理解できている方や先にpropsプロパティの説明を読みたい方はこちらまで飛ばして下さい。

ちなみに、受け渡すデータの「データ」が指しているものは3種類ほどあり、数値またやメソッド(関数の中でもプロパティの値になっている関数)、そしてイベントなどです。

そのうち、親コンポーネントから子コンポーネントに対するデータの受け渡しでは、親子コンポーネントが数値とメソッドという2種類のデータを受け渡します。

親コンポーネントと子コンポーネントの関係

propsプロパティの説明の前にコンポーネント同士の関係を表す言葉を解説します。

コンポーネントには親コンポーネントと呼ばれるものと、子コンポーネント呼ばれるものがあります。どのようなコンポーネントが、どちらの呼ばれ方をするのかを説明します。

まず、作られたコンポーネントには「コンポーネントの中に使われるコンポーネント」と、「アプリケーションの中に直接使われるコンポーネント」があります。

コンポーネントの中に使われるコンポーネントというのは、個人情報登録フォームやお問合せフォームを作るため共通して使う、メールアドレス入力欄のようなコンポーネントを指します。

一方で、アプリケーションの中に直接使われるコンポーネントというのは、アプリケーション内で何度も使うために作られる、個人情報登録フォームやお問合せフォームのようなコンポーネントを指します。

この2つのコンポーネント間の関係を表す時に、コンポーネントの中に使われているコンポーネントのことを「子コンポーネント」といい、その子コンポーネント利用したアプリケーション内で直接使われているをコンポーネントを「親コンポーネント」といいます。

使われている方のコンポーネントが「子コンポーネント」で、使っている方のコンポーネントが「親コンポーネント」だと考えて下さい。

この考え方から、コンポーネントがではありませんが、アプリケーション自体を「親コンポーネント」、このアプリケーションで直接使われるコンポーネントを「子コンポーネント」呼ぶこともがあります。

親コンポーネントであるか、子コンポーネントであるかは、そのコンポーネントが使われている側か使っている側かという「関係」で決まるため、コンポーネントがはいつも同じ呼ばれ方をするとは限りません。

親コンポーネントと子コンポーネントの関係がおわかりいただけたでしょうか?

親コンポーネントのデータ・子コンポーネントのデータ

次は、アプリケーションを親コンポーネントと呼ぶときに、親コンポーネントのデータとは何か、その子コンポーネントのデータとは何かを説明します。すでに知っている方 →「propsプロパティとは

親コンポーネントのデータ

親コンポーネントのデータとは、親コンポーネントの中で使われているデータのことです。例えば、次のようなHTMLがあったとします。

<div id="app">
    <p>{{ parentData }}</p>
</div>

このHTMLにある「parentData」は、親コンポーネント(アプリケーション)に直接使われているデータであるため「親コンポーネントのデータ」です。

親コンポーネントのデータは、Vueインスタンを作る時に渡す、オブジェクトのdataプロパティとmethodsプロパティに設定したプロパティ(A)に該当します。

コンポーネントのデータ

子コンポーネントのデータとは、子コンポーネントの中で直接使われているデータのことです。

例えば、コンポーネントを次のようにして作ります。

Vue.component("childComponent",{
    template: "<p>{{ childData }}</p>",
    data: function () {
        return {
            childData: "子のデータ"
        }
    }
})

作ったこのコンポーネントを、次のようにしてアプリケーションで使います。

<div id="app">
    <childComponent></childComponent>
</div>

このとき、「childComponent」というコンポーネントのp要素の中で、「childData」というデータが使われていますよね。

もちろんこのアプリケーションをブラウザに表示すると、「chiledData」の値である「子のデータ」という文字列が表示されます。

しかし、「chiledData」を使っている「childComponent」をアプリケーションで使っていることで、アプリケーションが「childData」を間接的に使っているだけです。

「childComponent」が「childData」を直接使っています。このときに、「childData」が「子コンポーネントのデータ」になります。

子コンポーネントのデータは、Vue.componen APIに渡した、第二引数のオブジェクトにあるdataプロパティが返したプロパティ(B)に該当します。

propsプロパティとは

propsプロパティとは、親コンポーネントのデータを子コンポーネントの中で使うときに設定するプロパティです。

そもそもpropsプロパティを使う必要はあるの?

propsプロパティを使わなくても、次のようにして「子コンポーネントの中で親コンポーネントのデータを使うことができるのでは?」と思う方もいらっしゃると思います。

HTML側

<div id="app">
    <childComponent></childComponent>
</div>

Javascript側

Vue.component("childComponent",{
    template: "<p>{{ parentData }}</p>"        //子コンポーネントの中ではparentDataを設定していない
})
const vm = new Vue({
    el: "#app",
    data: {
        parentData: "親のデータ"
    }
})

実は、このようなことはできないため、Chrome DevToolsには次のようなエラーメッセージが表示されます。

子コンポーネント内で親コンポーネントのデータを使えない理由は、親コンポーネントのdataプロパティの中身と、子コンポーネント(Vue.component APIに渡すオブジェクト)のdataプロパティの中身とがそれぞれ別々のスコープを持っているためです。

この異なるスコープでのデータの使用することをもし例えるとすると、2つの関数を定義したときに、それぞれの関数内では、定義していないがもう一方の関数で定義してある変数を使おうとしているようなことをしているイメージです。(厳密には違かった申し訳ありません)

var parent = function () {
    var parentData= "親のデータ";
    console.log(parentData);
}
var child = function () {
    var childData: "子のデータ";
    console.log(childData);    
    console.log(parentData);   //parent → undefined
}
child();    //parentData is not defined at child

そのため、子コンポーネントの中で親コンポーネントのデータを使うには、propsプロパティを使う必要があるのです。

propsプロパティの使い方

基本的な書き方

propsプロパティの基本的な書き方を説明します。

親コンポーネントが子コンポーネントに何を受け渡すかによって書き方が少し異なります。

それは、dataプロパティの中身を渡すか、それともmethodsプロパティの中身を渡すかです。

methodsの中身の場合、受け渡すのはメソッドであるため「v-on:click=”メソッドのキー”」のように、子コンポーネントの要素の属性値に使うことがあるためです。

dataプロパティの中身を渡す

HTML側

<div id="app">

    <子コンポーネントの名前 v-bind:子コンポーネントでのキー="親コンポーネントでのキー"></子コンポーネントの名前>
</div>

Javascript側

Vue.component("子コンポーネントの名前",{

    props: [ 親コンポーネントから受け取ったデータを子コンポーネントで使うときのキー ],    //配列の要素として受け取ります。
    template: "<p>{{ キー }}</p>"     //   
})
const vm = new Vue({
    el: "#app",
    data: {
        子コンポーネントに渡すデータのキー: 子コンポーネントに渡すデータ(値)
    }
})

同じ色がついている部分は全く同じものを記述することを意味しています。

methodsプロパティの中身を渡す

HTML側

<div id="app">

    <子コンポーネントの名前 v-bind:子コンポーネントでのキー="親コンポーネントでのキー"></子コンポーネントの名前>
</div>>

Javascript側

Vue.component("子コンポーネントの名前",{

    props: [ 親コンポーネントから受け取ったデータを子コンポーネントで使うときのキー ],    //配列の要素として受け取ります
    template: "<button v-on:click="キー()">ボタン</button>"  //メソッドに引数がなければ()は付けても付けなくてもいいです 
})
const vm = new Vue({
    el: "#app",
    methods: {
        子コンポーネントに渡すデータのキー: 子コンポーネントに渡すデータ(メソッド)
    }
})

子コンポーネントにメソッドを受け渡す際の注意があります。それは、メソッドを実行せずにメソッドの情報だけを渡す場合、メソッドのキーに()を付けないようにする点です。

受け渡す側でメソッドのキーに()を付けてしまうと、うまくメソッドの情報を受け渡せないことがあるため、気をつけて下さい。

サンプルプログラム

親コンポーネントから子コンポーネントへのデータの受け渡し方は、だいたいわかったでしょうか。

受け渡しができても、いったいどのようなときに親から子へ受け渡すと便利なのか、いまいちわからないかもしれません。

そこで、サンプルプログラムを使って、どういうときに親コンポーネントから子コンポーネントへのデータの受け渡しが必要になるのか考えてみましょう。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>propsプロパティ</title>
  <script src="https://unpkg.com/vue"></script>
</head>
<body>
  <div id="app">
    <contact-page></contact-page>
    <personal-information-page></personal-information-page>
  </div>
  <script>
    Vue.component("formComponent", {
      props: ["title", "formNames"],
      template: `
                <div>
                    <h1>{{ title }}</h1>
                    <div v-for="(formName, key) in formNames" v-bind:key="key">
                        <p>{{ formName }}</p>
                        <input type="text" name="key">
                    </div>
                </div>                `
    })
    Vue.component("contactPage", {
      template: "<form-component v-bind:title='title' v-bind:form-names='page'></form-component>",
      data: function () {
        return {
          title: "お問合せ",
          page: {
            name: "お名前",
            eMail: "Eメールアドレス",
            content: "お問い合わせ内容"
          }
        }
      }
    })
    Vue.component("personalInformationPage", {
      template: "<form-component v-bind:title='title' v-bind:form-names='page'></form-component>",
      data: function () {
        return {
          title: "個人情報のご入力",
          page: {
            name: "お名前",
            age: "年齢",
            adress: "住所"
          }
        }
      }
    })
    const vm = new Vue({
      el: "#app"
    })
  </script>
</body>
</html>

まずはこのプログラミングをブラウザに表示したものを見てみましょう。

上のサンプルプログラムでは、お問い合わせフォームのコンポーネントである「contactPage」と個人情報入力フォームのコンポーネントである「personalInformationPage」の2つ作成し、アプリケーション内でこの2つを使っています。

さらに、この2つのコンポーネントには共通して、「formComponent」というコンポーネントを使っています。

つまり、「contactPage」と「personalInformationPage」が「formComponent」の親コンポーネントです。

子コンポーネントである「contactPage」は親コンポーネントに受け渡された、オブジェクト型のデータを使って、フォームのタイトルと、複数の入力欄を表示します。

子コンポーネントが使われる親コンポーネントが持っているデータによって、子コンポーネントの中身を変えなくても、異なる2つのフォームを表示することができるのです。

このように、複数の親コンポーネントで似たような機能を持った部品を使う際に、使われる親コンポーネントによって柔軟に表示内容を変化させる必要がある場合には、propsプロパティが非常に便利です。

今回の説明はここで終わりにします。次回は、今回のデータの受け渡しと逆の方向である「子コンポーネントから親コンポーネントへのデータの受け渡し」について説明します。

まとめ

今回わかったこと

  • 2つのコンポーネント間には親と子の関係が存在する
  • propsプロパティを使うことで、親コンポーネントから子コンポーネントへのデータの受け渡しができる
  • 使われる親コンポーネントによって、子コンポーネント表示を変えたいような場面でpropsプロパティによる受け渡しは便利

コメント

タイトルとURLをコピーしました