vueのpropsとemitを使ったコンポーネント間の値の受け渡し

##1.はじめに
Vueのコンポーネントを学習する中で、propsとemitの理解が難しかったので、ここでまとめたいと思います。

記事の中に検証ソースをあげますが、webpack(ver:4.41.6)で動かしておりファイル構成は以下の通りです。

```
├─public
│  ├── bundle.js
│  └── index.html
├─src/
  ├── components
  │   ├── emitChild.vue
  │   ├── parent.vue
  │   └── propsChild.vue
  └── index.js
```

本記事ではpublic/index.htmlへ親コンポーネントを使用します。よってindex.htmlは以下の内容で固定です。

```public/index.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>VueComponent</title>
</head>
<body>
  <div id="app">
  <parent></parent>
  </div>
  <script src="/public/bundle.js"></script>
</body>
</html>
```

webpackの使い方は以下のQiita記事を参照しているため、こちらで確認してください。
[webpack4入門](https://qiita.com/soarflat/items/28bf799f7e0335b68186)



##2.propsについて
propsは親⇨子へ値を受け渡す際に使用するプロパティです。
親コンポート内に、v-bindで定義したプロパティの値を子へ受け渡します。

以下の画面をpropsを使って表示します。
![スクリーンショット 2020-02-17 16.12.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275345/a8269521-7364-623a-b182-1958b521a4ca.png)



parentとpropsChildのファイルを編集します。

```src/components/parent.vue

<template>
    <div id="parent-area">
        <!-- 子コンポーネントへ受け渡すcontext,numberを定義 -->
        <propsChild :context="text" :number="num"></propsChild>
    </div>
</template>

<script>
import propsChild from "./propsChild.vue";

export default {
    components:{
        emitChild:emitChild,
        propsChild:propsChild,
    },
    data(){
        return {
            // 受け渡す値はdataプロパティで設定しないとエラーするので注意
            text:'このテキストを子コンポーネントへ受け渡します',
            num:1000
        }
    }
}
</script>
```

親コンポーネントで子コンポーネントを定義する際に、v-bindでpropsへ渡すプロパティを定義します。
私自身つまづいたところですが、propsプロパティ（context）へ渡すのは値は、vueで定義済みのプロパティ(text:dataで定義したプロパティ等)の必要があります。
直接値を埋め込むと定義されていないとエラーしますので注意しましょう。

```src/components/propsChild.vue
<template>
    <div id="props-area">
        <h3>Props Area</h3>
        <p>Content:{{context}}</p>
        <p>Number:{{number}}</p>
    </div>
</template>

<script>
export default {
    // 親コンポーネントで定義したプロパティをpropsで定義して受け取る
    props:{
        context:String,
        number:Number
    },
}
</script>
```

propsの定義は上記のようにしていますが、他にも記述方法があり、型のバリデーションやオブジェクトの定義などが可能です。
上の例では、String型とNumberのバリデーションをしています。
[公式ドキュメント](https://jp.vuejs.org/v2/guide/components-props.html)に詳細があるので一度眺めるのがいいと思います。


##3.emitについて
emitは子⇨親へ値を受け渡す方法です。（ここは理解するのにちょっと苦戦しました。。。）
子⇨親のデータ受け渡しはイベントを利用して行います。

以下のような動的ページをemitを使い表示します。
EimitAreaで入力した値を親コンポーネントのResultAreaへ表示します。

![vue_emit.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275345/c7652f28-03e1-3792-f861-4b6d42e5ede8.gif)



parentとemitChildのファイルを編集します。

```src/components/parent.vue
<template>
    <div id="parent-area">
        <!-- 「emit-event」は子コンポーネントと繋ぐ定義、「receive」は親コンポーネントで子コンポーネントからの値を取得するためのメソッド -->
        <emitChild @emit-event="receive"></emitChild>

        <div id="result">
            <!-- 子コンポーネントからの値を表示するエリア -->
            <p>Result Area</p>
            <p>Result Text:{{result1}}</p>
            <p>Result Number:{{result2}}</p>
        </div>
    </div>
</template>

<script>
import emitChild from './emitChild.vue';

export default {
    components:{
        emitChild:emitChild,
    },
    data(){
        return{
            result1:'',
            result2:''
        }
    },
    methods:{
        receive(data1, data2){
            //data1,data2は子コンポーネントから受け取った値
            this.result1 = data1;
            this.result2 = data2;
        }
    }
}
</script>
```

親と子のコンポーネントを繋ぐイベント（emit-event）を親の中の子コンポーネントで定義します。
また、methodsプロパティでは、子コンポーネントからの値を受け取ります。
data1,data2の引数は子コンポーネントから受け取った値になります。

```src/components/emitChild.vue
<template>
    <div id="emit-area">
        <p>Emit Area</p>
        <label>Text:<input type="text" v-model="context"></label>
        <label>Number:<input type="number" v-model="number"></label>
        <button @click="onClickEmit">送信</button>
    </div>
</template>

<script>
export default {
    data(){
        return{
            context:'',
            number:0,
        }
    },
    methods:{
        onClickEmit(){
            //親コンポーネントで定義した「emit-event」を第一引数へ定義し、以降の引数は親コンポーネントへ渡す値を定義
            this.$emit('emit-event', this.context, this.number);
        }
    }
    
}
</script>
```

ここでは子コンポーネントのmethodsで親コンポーネントへ値を渡します。なので、必ずしもclickイベントで定義しなくてはいけないわけではありません。
$emitの第一引数には、親コンポーネントで定義したイベントを入れて、以降の引数には親コンポーネントへ渡す値を入れてあげます。
なので、親コンポーネントのmehods>receiveイベントの引数（data1、data2）はここのthis.content,this.number）となります。



##4.コンポーネント間の値の受け渡しの例
以下のようなコンポーネント間で値の受け渡しをやってみます。


```
emitChild ⇨　parent ⇨　propsChild
```

※2,3章で使ったemitchildとpropsChildのソース内容は上書きして以降は使っていきます。

最終的なページの動きは以下の通りです。
![vue2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275345/58d2116b-0058-719d-7a3a-34b966338aff.gif)


``````src/components/parent.vue
<template>
    <div id="parent-area">
        <!-- <emitChild v-model="content"></emitChild> -->
        <emitChild :value="content" @input="content = $event.target.value"></emitChild>
        <propsChild :text="content"></propsChild>
    </div>
</template>

<script>
import emitChild from './emitChild.vue';
import propsChild from './propsChild.vue';

export default {
    components:{
        emitChild:emitChild,
        propsChild:propsChild,
    },
    data() {
        return {
            content:'',
        }
    },
}
</script>
```

emitChildで子コンポートからの値を取得しています。
また、この書き方はv-modelでも置換可能です。理由とすると、v-modelを解体すると以下の書き方ためです。([公式リファレンス参照](https://jp.vuejs.org/v2/guide/components.html#%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E3%81%A7-v-model-%E3%82%92%E4%BD%BF%E3%81%86))


```
<input
  v-bind:value="searchText"
  v-on:input="searchText = $event.target.value"
>
```

この$eventはinputタグのインスタンスなため、[inputタグのメソッド](https://developer.mozilla.org/ja/docs/Web/API/HTMLElement/input_event)が利用可能になります。



``````src/components/emitChild.vue
<template>
    <div id="emit-area">
        <h3>Emit Area</h3>
        <textarea :value='context' @input="OnInput"></textarea>
    </div>
</template>

<script>
export default {
    methods: {
        OnInput($event){
            this.context = $event.target.value;
            // 引数へinputイベントを投げます
            this.$emit('input', $event);
        }
    },
    data() {
        return {
            context:''
        }
    },
}
</script>
```

```src/components/propsChild.vue
<template>
    <div id="props-area">
        <h3>Props Area</h3>
        <p>{{text}}</p>
    </div>
</template>

<script>
export default {
    props:{
        text:String,
    },
}
</script>
```

emitChildとpropsChildのemit、propsの使い方は前章とほぼ同様です。



##5.まとめ
vueのpropsとemitが自分的にわかりにくかったのでまとめてみました。
値の受け渡しによって、コンポーネントの部品としての可用性が上がり、細分化が可能だと思うので積極的に使っていこうと思います。
また記事内で間違いがあればご指摘お願いいたします。

##6.参照
[Vue.jsコンポーネント入門 (5) コンポーネント間のコミュニケーション](https://www.hypertextcandy.com/vuejs-components-introduction-communication-between-components)
[【Vue.js】 コンポーネント間の通信について解説](https://se-tomo.com/2018/11/03/vue-js-%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E9%96%93%E3%81%AE%E9%80%9A%E4%BF%A1/)