Vue.js における Component 間のデータの受け渡しまとめ

## Overview

Vue.js を使っていて、この Component 間の関係だとどうやって data 渡すんだっけな...？
となることが多いので方法はいろいろあると思いますが、自分がよくやるやり方をこの記事にまとめておきます。
(他にもこんなやり方あるよ！という知見ありましたら教えていただけますと幸いです :pray: )


## 親 → 子

親 Component から 子 Component へのデータの受け渡しは、
**親 Component で data を v-bind して、子 Component で props で data を引き取ります。**

### Sample Code

- **Parent.vue ( v-bind で data を渡す)**

```vuejs
<template>
  <div id="parent">
    <child v-bind:messageFromParent="this.message" />
  </div>
</template>

<script>
import Child from './Child'

export default {
  name: 'Parent',
  data () {
    return {
      message: 'Hello from Parent!'
    }
  },
  components: {
    child: Child
  },
}
</script>
```

- **Child.vue ( props で引き取る)**

```vuejs
<template>
  <div id="child">
    {{ messageFromParent }}
  </div>
</template>

<script>
export default {
  name: 'Child',
  props: ['messageFromParent']
}
</script>
```

## 子 → 親

逆に、子 Component から 親 Component への data の受け渡しは
**親 Component で v-on でイベントハンドラを定義しておき、子 Component では $emit で data を持たせて 親 Component で提起しているイベントを発火させます。**

※ emit : 放つ、放射する 

### Sample Code

- **Parent.vue ( v-on でイベントハンドラを定義する)**

```vuejs
<template>
  <div id="parent">
    <child v-on:sendMessage="receiveChildMessage" />
    {{ this.childMessage }}
  </div>
</template>

<script>
import Child from './Child'

export default {
  name: 'Parent',
  data () {
    return {
      childMessage: ''
    }
  },
  components: {
    child: Child
  },
  methods: {
    receiveChildMessage (message) {
      this.childMessage = message
    }
  }
}
</script>
```

- **Child.vue ( $emit で data を持たせつつ、親のイベントを発火する)**

```vuejs
<template>
  <div id="child"/>
</template>

<script>
export default {
  name: 'Child',
  data () {
    return {
      message: 'Hello from Child!'
    }
  },
  created () {
    this.$emit('sendMessage', this.message)
  }
}
</script>
```

## 子A → 子B

これは実装の方針が人によって分かれそうなのですが、自分は **２つ以上の Component にまたがって data の受け渡しを行う場合 (子A → 親 → 子B 、 親 → 子 → 孫 など) Vuex を使うことが多いです。**

※ Vuex についての詳細はこちらをご参照ください。
https://vuex.vuejs.org/ja/

### Sample Code

- **store.ts**

```ts
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

interface State {
  message: string
}

const initState: State = {
    message: ''
};

export default new Vuex.Store({
  state: initState,
  mutations: {
    setMessage(state, { message }: { message: string }) {
      state.message = message;
    }
  }
})
```

- **Parent.vue ( store を import する)**

```vuejs
<template>
  <div id="parent">
    <child-a />
    <child-b />
  </div>
</template>

<script>
import store from './store'
import ChildA from './ChildA'
import ChildB from './ChildB'

export default {
  name: 'Parent',
  store,
  components: {
    child-a: ChildA,
    child-b: ChildB
  },
}
</script>
```

- **ChildA.vue ( Vuex に data を store する)**

```vuejs
<template>
  <div id="child-a"/>
</template>

<script>
export default {
  name: 'ChildA',
  created () {
    this.$store.commit('setMessage', { message: 'Hello from ChildA!' });
  }
}
</script>
```

- **ChildB.vue ( Vuex から data を参照する)**

```vuejs
<template>
  <div id="child-b"/>
  {{ this.message }}
</template>

<script>
export default {
  name: 'ChildB',
  data () {
    return {
      message: ''
    }
  },
  created () {
    this.message = this.$store.state.message
  }
}
</script>
```

### まとめ

- 親 Component → 子 Component

`(親) v-bind:'value'` → `(子) props['value']`

- 子 Component → 親 Component

`(子) this.$emit('childHandler', value)` → `(親) v-on:childHandler="parentHandler"`

- 子 Component A → 子 Component B

`(子A) Vuex に data を store` → `(子B) Vuex から data を参照`