フロントエンド

【Vue3 props/emit】コンポーネント間通信

Vue3コンポーネント間通信

reisuta

Webエンジニア | 20代中盤 | 大学時代はGmailすら知らないIT音痴でプログラミングとは無縁の生活を送る → 独学でプログラミングを学ぶ → Web系受託開発企業にエンジニアとして就職 → Web系自社サービス企業に転職 | 実務未経験の頃からVimを愛好しており、仕事でもプライベートでも開発はVimとTmuxを使っているので、VSCodeに疎いのが最近の悩み。何だかんだでやっぱりRubyが好き。

コンポーネントとは?

コンポーネントとは、そのままの意味としては、
部品とか、構成要素とかといったものがあります。

Vue.jsにおけるコンポーネントという概念も、
大まかにはそのような意味で、
より具体的に言うと、
ボタンとか、ヘッダーとか、Webページの構成要素を指しています。

具体例を出します。

<script setup lang="ts">
import { ref } from 'vue'
import Aim from './Aim.vue'
const isShow = ref(true)
const change = () => {
  if (isShow.value) {
    isShow.value = false
  } else {
    isShow.value = true
  }
}
</script>

<template>
  <Aim v-if="isShow" />
  <button @click="change" class="rounded-lg m-2 p-2 border border-gray-300 bg-gray-100">isShow</button>
</template>

たとえば、このコードの場合、
Aim.vueというコンポーネントをimportして、
使用しています。

左側のテストと言う部分が、
Aimコンポーネントです。

このように、Webページの構成要素となるものを、
コンポーネントといいます。

通常、コンポーネントは.vueファイルに定義され、
親(コンポーネントを使用する側)でimportをします。

なぜコンポーネントとして切り出すのかというと、
再利用性を高めて、コードの保守性や見通しを良くするためです。

例えば、同じようなボタンが何度も記述されていては、
冗長なので、ボタンのコンポーネントを.vueファイルに定義して、
何度も使い回せるようにするという感じです。

ちなみに、.vueファイルにコンポーネントを定義することを、
単一ファイルコンポーネント(SFC)と言うらしいです。

https://ja.vuejs.org/guide/essentials/component-basics.html

コンポネント間通信

コンポネントのメリットは、これだけではなく、
それぞれが独立していて、親から子へのデータの受け渡し、
通信をすることもできる点があります。

この子から親、親から子のデータの受け渡しの方法として、
Vue.jsには、propsとemitというものがあります。

以下、この2つについて解説します。

props

propsとは、親コンポーネントから子コンポーネントにデータを
渡す仕組みのことです。

props自体は、Vue.js独自の概念ではなく、
Reactとかにも存在します。

具体例として、子コンポーネントとして、
Child.vueを作成してみます。

<template>
  <div>
    <p>Prop A: {{ propA }}</p>
    <p>Prop B: {{ propB }}</p>
  </div>
</template>

<script setup lang="ts">
const props = defineProps({
  propA: {
    type: String,
    required: true
  },
  propB: {
    type: Number,
    default: 100
  }
})
</script>

Vue3のComposition APIでは、
definePropsという関数を使ってpropsを定義します。

上記の場合、propAとpropBという2つのpropsが定義されています。

これを親から呼び出す場合は、

<script setup lang="ts">
import { ref } from 'vue'
import Aim from './Aim.vue'
import Child from './Child.vue'
const isShow = ref(true)
const change = () => {
  if (isShow.value) {
    isShow.value = false
  } else {
    isShow.value = true
  }
}
</script>

<template>
  <Aim v-if="isShow" />
  <Child
    prop-a="hello world"
    prop-b="399"
  />
  <button @click="change" class="rounded-lg m-2 p-2 border border-gray-300 bg-gray-100">isShow</button>
</template>

先程の、TheWelcom.vueに追記しました。
Aimコンポーネントと同様に、Childコンポーネントもインポートしています。

その際、prop-aという感じで、
definePropsで定義されているpropsを渡しています。

この場合、hello worldという文字列をChildコンポーネントに渡しています。

変数をpropsにわたす場合は、
prop-a="hello world"の部分を

  <Child
    :prop-a="greeet"
    prop-b="399"
  />

というように、
v-bindを使用すると渡すことができます。

v-bindとはなんぞや?って言う人は、
こちらの記事で解説しているので、
詳細はこちらを御覧ください。

Vue3双方向データバインディング
参考【Vue3/v-model】双方向データバインディングとは?

Vue.jsの概念に、双方向データバインディングというものがあります。 これは、単方向データバインディングに対するものです。 本記事では、双方向データバインディングの解説を通して、単方向データバインデ ...

続きを見る

emit

次にemitです。

propsが親から子へのデータの流れに対して、
emitは、その反対の子から親へのデータの流れに対応します。

<!-- 親 -->
<script setup lang="ts">
import { ref } from 'vue'
import Child from './Child.vue'
const greet = 'hello gwge'
const print = ():void => {
  console.log('emit')
}
</script>

<template>
  <Child
    :prop-a="greet"
    prop-b="399"
    @submit="print"
  />
</template>
<!-- 子 -->
<template>
  <div>
    <p>Prop A: {{ propA }}</p>
    <p>Prop B: {{ propB }}</p>
  </div>
  <button @click="submit">Submit</button>
</template>

<script setup lang="ts">
const props = defineProps({
  propA: {
    type: String,
    required: true
  },
  propB: {
    type: Number,
    default: 100
  }
})
const emit = defineEmits(["submit"])
const submit = () => {
  emit("submit")
}
</script>

emitは、Vue3 Composition APIの場合、
子の方に、defineEmitsという形で定義し、
emit("submit")で親のv-onディレクティブのsubmitを探しにいき、
そこのメソッドを実行し、printメソッドが走っているという流れです。

propsのときと同じく、
defineEmitsなどは、基本的に子の方で定義します。

emitは、Reactなどには存在せず、
Vue.js独特の機能です。

Vue.jsは双方向データバインディングを特徴に持つため、
このようなpropsとemitという2つのパターンがあります。

チームやPJの方針にもよりますが、
無思考でpropsやemitをたくさん書いてしまうと、
データの流れがカオスになるので、
「こういうときはprops、こういうときはemit」という風に、
大まかな方針を決めておくのがいいかなと思います。

  • この記事を書いた人
  • 最新記事

reisuta

Webエンジニア | 20代中盤 | 大学時代はGmailすら知らないIT音痴でプログラミングとは無縁の生活を送る → 独学でプログラミングを学ぶ → Web系受託開発企業にエンジニアとして就職 → Web系自社サービス企業に転職 | 実務未経験の頃からVimを愛好しており、仕事でもプライベートでも開発はVimとTmuxを使っているので、VSCodeに疎いのが最近の悩み。何だかんだでやっぱりRubyが好き。

おすすめ記事はこちら

Vim/Neovimプラグイン 1

プラグインをどれだけ入れるかは、その人の思想なども関係するので、一概にこれがいいというのはないかもしれません。 プラグインを全く入れない人もいれば、100個以上入れる人もいます。 ただそれでも、これだ ...

VimとNeovimの比較 2

本記事では、VimとNeovimの違いについて、解説します。 VimとNeovimの違いについては、普段頻繁にVimなどを使う方でなければ、正直、あまり気にしなくてもいいかなと思います。 ただ、Vim ...

Ruby変数やすべてがオブジェクトについて 3

本記事は、Rubyの基礎文法である、変数や真偽値、論理演算子に触れると同時に、「すべてがオブジェクト」というRubyの特徴的な思想についても解説します。 この思想は、Rubyの文法の根幹になっているの ...

4

エンジニアにおすすめの技術書 書籍学習は、エンジニアの嗜みみたいなところがありますが、 良書というものは、意外とそこまで多くもありません。 そこで本記事では「技術書マニアの筆者が厳選した技術書20選」 ...

5

エンジニアになるには? プログラミングは、専門性が高く自分一人で勉強するのが大変に感じることも多いですよね。 そこで本記事では「おすすめのプログラミングスクール5選」を特徴と、現役エンジニア目線で優れ ...

-フロントエンド