Vue.js+Typescriptのpropsとemitの使い方

# 1.@Propコンポーネント間のデータの受け渡し（親→子）

### Vue.js+Typescriptde+vue-property-decoratorでpropsとemitを使うときの備忘録。


#### ＜Prop編＞
親コンポーネントでは、子コンポーネントタグに子コンポーネントのプロパティ名をケバブケースで命名する。
（今回は、子コンポーネントのプロパティ名は「`YourDinner`」のため、親コンポーネントの属性名は「`your-dinner`」になる。）

```typescript:親コンポーネント
<Component your-dinner="カレーライス"></Component>
```
　　　　　　　　　　　　　　　　　　　　⬇︎　　　**Props down**

子コンポーネントでは、@Propデコレーターをつけたプロパティで受け取る。

```typescript:子コンポーネント
@Prop({default:"なし"})
yourDinner!: string; //←上記の親コンポーネントで渡した「カレーライス」が入る。
```




親コンポーネントから渡ってくる値を受け取る`yourDinner`変数を定義。
値が渡ってこなかった場合は、default内の値が`yourDinner`変数に代入される。
デフォルト値を設定しない場合は以下のように（）内に何も入れなくていい。

```typescript:子コンポーネント
@Prop()
```

また、子コンポーネントでは今まで通り以下のように初期化はしない。

```typescript:子コンポーネント
yourName="";
```

このようにしてしまうと、毎回`yourName`に空文字が代入されて、親コンポーネントから値が渡されない。
しかし、空文字で初期化をしないと、トランスコンパイル時に「初期化されていない」というエラーが出てしまう。

「!」マークをつけることで、「初期化されていないが問題ない」ということをトランスコンパイラに伝えることができる。
また、TypeScriptでは初期値で変数の方を推論するが、初期化していないため、「`:string`」をつけて型指定をする。


＜サンプルコード＞

```typescript:components/sample/CompPropsYourDinner.vue（子コンポーネント）
<template>
   <div class="sample">
     <div>あなたの夕食は、{{yourDinner}}です。</div>
   </div>
</template>

<script lang=ts>
import { Prop, Component, Vue } from "vue-property-decorator";
@Component
export default class CompPropsYourDinner extends Vue {
  @Prop({ default:"なし"})
  yourDinner!:string;
}

</script>

```

＠Propデコレーターを使用するためには、`"vue-property-decorater"`からインポートする必要がある。

```typescript:親コンポーネント
<template>
  <div class="sample">
    <CompPropsYourDinner your-dinner="カレーライス"></CompPropsYourDinner>
    <CompPropsYourDinner your-dinner="親子丼"></CompPropsYourDinner>
    <CompPropsYourDinner></CompPropsYourDinner>
  </div>
</template>

<script lang="ts">
import { Component, Vue } from "vue-property-decorator";
import CompPropsYourDinner from "@/components/sample/ComPropsYourDinner.vue";
@Component({
  Component: {
    CompPropsYourDinner,
  },
})
export default class PropsParent extends Vue {}
</script>
```

３行目と４行目でそれぞれ、「カレーライス」と「親子丼」を子コンポーネントに渡している。
５行目では`your-dinner`属性が存在せず、値を渡していないのでデフォルト値の「なし」が`youeDinner`に入ることになる。


# 2.@Emit コンポーネント間のデータの受け渡し（子→親）

親コンポーネントで子コンポーネントで発生したイベントを拾う。
例）モーダル画面をクローズする場合

```typescript:親コンポーネント
<LogoutModal v-on:close-modal="closeModal"></LogoutModal>
```

　　　　　　　　　　　　　　　　　　　　　　　⬆︎

子コンポーネントでは@Emitデコレーターをつけたメソッドでイベントを発生させる。

```typescript:子コンポーネント
<button class="btn" vclick="closeModal">モーダルを閉じる</button>

@Emit()
  public closeModal): void {
    console.log("close-modalイベント発生");
  }
```

子コンポーネントの`closeModal()`メソッドに@Emit()デコレーターを付けることで、`close-modal()`イベントが発生して、親コンポーネントに伝わる。
HTMLの特性で大文字、小文字を区別しないので、以下のようにかくことになる。
　　　　メソッド名：`closeModal`（キャメルケース）←子コンポーネント
　　　　イベント名：`close-modal`（ケバブケース）←親コンポーネント


<サンプルコード>

```typescript:子コンポーネント
<template>
  <div class="sample">
    <button class="btn" v-on:click="closeModal">モーダルを閉じる</button>
  </div>
</template>

<script lang="ts">
import { Emit, Component, Vue } from "vue-property-decorator";
@Component
export default class CompModalEmit extends Vue {
  @Emit()
  closeModal(): void {
    console.log("close-modalイベント発生！");
  }
}
</script>
```


`closeModal()`メソッドについている@Emitデコレータは、イベントを発生させるデコレータで、同じメソッド名のイベントが発生して親コンポーネントに伝わる。
（このとき、子コンポーネントではキャメルケースのメソッド名だが、親コンポーネントではケバブケースに変換される）


```typescript:親コンポーネント
<template>
  <div class="sample">
    <button @click="openModal">モーダルを開く</button>
    <CompModalEmit v-on:close-modal="closeModal" v-if="isModalOpen">
    </CompModalEmit>
  </div>
</template>

<script lang="ts">
import { Component, Vue } from "vue-property-decorator";
import CompModalEmit from "../../components/sample/CompModalEmit.vue";
@Component({
  Components: {
    CompModalEmit,
  },
})
export default class EmitParent extends Vue {
  //モーダルの表示ステータス
  private isModalOpen = false;

  //モーダルを開く処理
  openModal(): void {
    this.isModalOpen = true;
  }

  //モーダルを閉じる処理
  closeModal(): void {
    this.isModalOpen = false;
  }
}
</script>
```

`v-on:close-modal="closeModal`で子コンポーネントで発生した`close-modal()`イベントを拾って、親コンポーネントの`closeModal()`メソッドを呼ぶ。

## まとめ

データの受け渡しをするときは、
・親コンポーネントは、ケバブケース
・子コンポーネントは、キャメルケース
でメソッド名を書く。

親から子はPropで、子から親はEmit。