1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Vueのpropsと$emitを使ってコンポーネント間でデータをやりとりする

Posted at

はじめに

Vue で親コンポーネントと子コンポーネントの間でデータをやり取りする方法について、今まで何となくやっていたので改めて勉強しました。
分かりにくい部分だと思うので、よかったら参考にして頂ければと思います。

対象者

  • 基本的な JavaScript のコーディングができる方
  • Vue で開発をしたことがある方

環境

  • Vue.js 2.6.10
  • Vuetify 2.1.0

勉強しながら作ったもの

名前と血液型を入力する子コンポーネントを作りました。
親コンポーネントから初期値を渡して初期表示したり、子コンポーネントで入力した名前・血液型を親コンポーネントに渡したりできるようにしています。

下の画像がスクリーンショットで、氏名から【反映】ボタンまでの3段が子コンポーネントで、parent: の段が親コンポーネントです。

スクリーンショット 2021-05-22 17.03.20.png

親子間のデータやりとりについて

作ったものの説明の前に親子間のデータやり取りの基本に触れておきます。

親 → 子 のデータフロー

親は子に渡すデータを属性として指定します。
子はそれを props で受け取ります。
下記の例では、名前を value で親子間で一致させています。

<child :value="param"></child>
<script>
export default {
  props: {
    value: {
      name: String,
      bloodType: String
    }
  }
}
</script>

子 → 親 のデータフロー

子は親に渡すデータを $emit で渡します。
$emit で親側のイベントを発火させて、データが渡ります。

下記の場合、子で $emit を実行すると this.inputs を引数として親の input イベントが発火します。親側では value に子が指定した引数が渡ります。

<child @input="value => param = value"></child>
this.$emit('input', this.inputs)

親コンポーネントの記述をまとめる

上記の 親 → 子 子 → 親 で説明した親コンポーネントの実装内容をまとめると次のようになります。

<child
  :value="param"
  @input="value => param = value"
>
</child>

なお次のように v-model を使うと属性一つで記述できます。

<child v-model="param"></child>

作ったものの説明

それぞれのコンポーネント内のデータの状態を確認したいので、本来の入力項目以外に {{ }} を使ってデータをダンプしています。

子コンポーネント

コード
Child.vue
<template>
  <v-row>
    <v-col>
      <v-text-field v-model="name"></v-text-field>
      <v-radio-group v-model="bloodType" row>
        <v-radio
          v-for="elem in bloodTypes"
          :key="elem.value"
          :label="elem.label"
          :value="elem.value"
        ></v-radio>
      </v-radio-group>
      <v-btn @click="handleClick">反映</v-btn>
      {{ inputs }}
    </v-col>
  </v-row>
</template>

<script>
export default {
  props: {
    value: {
      name: String,
      bloodType: String
    }
  },
  data: () => ({
    name: '',
    bloodType: '',
    bloodTypes: [
      { label: 'A型', value: 'a' },
      { label: 'B型', value: 'b' },
      { label: 'O型', value: 'o' },
      { label: 'AB型', value: 'ab' }
    ]
  }),
  computed: {
    inputs: function () {
      return {
        name: this.name,
        bloodType: this.bloodType
      }
    }
  },
  created () {
    this.name = this.value.name
    this.bloodType = this.value.bloodType
  },
  methods: {
    handleClick () {
      this.$emit('input', this.inputs)
    }
  }
}
</script>

<template>

  • 【反映】ボタンを押すと handleClick 関数が実行され、$emit により親コンポーネントに入力内容が伝わります

<script>

  • propsvalue に、親コンポーネントで指定した値(初期値)が設定されます
    • 親側では :valuev-model で初期値を指定します
  • created で親コンポーネントから指定された値を data 配下にバラして設定しています
  • computedinputs は、子コンポーネントで入力された値を親コンポーネントへ反映するためのオブジェクトです
  • methodshandleClick 関数で this.$emit して親コンポーネントに反映します
    • 反映ボタンを押したときに動きます

親コンポーネント

コード
Parent.vue
<template>
  <v-container>
    <v-row>
      <v-col>
        <child v-model="param"></child>
        parent: {{ param }}
      </v-col>
    </v-row>
  </v-container>
</template>

<script>
import Child from './Child'

export default {
  components: {
    'child': Child
  },
  data: () => ({
    param: {
      name: 'hoge',
      bloodType: 'a'
    }
  })
}
</script>

<template>

  • 子コンポーネントを使用します
    • v-model で子コンポーネントに渡す値を指定します
    • :value でも値を渡すことができます
      • その場合は前述の通り @input 指定も必要になります

<script>

  • import で子コンポーネントをインポートします
  • components で子コンポーネントをコンポーネント定義します
  • data には子コンポーネントに初期値として渡す値を定義します
    • 子コンポーネントで値が書き換えられて $emit されると、ここが書き換わります

動かしてみる

名前や血液型を入力して【反映】を押すと、親コンポーネントに入力内容が伝わります。
ダンプされている内容から確認できると思います。

  • 【反映】ボタンの右は、子コンポーネント側の値
  • parent: の右は、親コンポーネント側の値

ezgif-3-c4b39a16f4c1.gif

処理の流れ

  1. 氏名や血液型の欄を編集する
    1. 子コンポーネントの data の中が書き換わる
    2. この時点では親コンポーネントには反映されない
  2. 【反映】ボタン押す
    1. 子コンポーネントの handleClick 関数により $emit される
    2. 子コンポーネントで入力された値が、親コンポーネントに伝わる

所感

今回勉強したことで、今まで何となくだった理解が深まって良かったと思っています。でもやっぱりしばらくするとまた忘れそうなので、記事見て思い出そうと思います。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?