Vue.jsの$emit完全ガイド|親子コンポーネント間で値を渡す方法
Vue.jsでコンポーネントを使って開発していると、必ずといってよいほど出てくるのが親コンポーネントと子コンポーネントのデータ受け渡しです。
特に、子コンポーネントで起きた操作や入力内容を親コンポーネントに伝えたい場面では、$emit が重要な役割を果たします。
たとえば、次のようなケースです。
-
子コンポーネントのボタンクリックを親に通知したい
-
フォーム入力の変更を親に渡したい
-
子コンポーネントで選択した値を親側で管理したい
-
モーダルを閉じる処理を親側で制御したい
-
再利用コンポーネントからイベントを発火して親で受け取りたい
Vue.jsでは、基本的にデータは親から子へ props で渡し、子から親へはイベントで通知するという流れで設計します。
この「子から親への通知」を実現するのが $emit です。
しかし初心者のうちは、次のような疑問を持ちやすいです。
-
$emitは何のために使うのか -
props とはどう違うのか
-
$emitで値を渡すにはどう書けばいいのか -
複数の値を渡せるのか
-
v-modelと$emitはどう関係しているのか -
Composition API ではどう書くのか
-
$emitが動かないときは何を確認すればよいのか
この記事では、Vue.jsの $emit について、基礎から実践、よくあるミス、Composition APIでの書き方、v-modelとの関係、エラー時の対処法までできるだけわかりやすく解説します。
「なんとなく使う」のではなく、なぜそう書くのかまで理解できるように丁寧に整理していきます。
$emitとは何か
$emit は、子コンポーネントから親コンポーネントへイベントを発火するための仕組みです。
Vue.jsでは、親子コンポーネント間のデータの流れは次のように考えるのが基本です。
-
親 → 子 :
propsで値を渡す -
子 → 親 :
$emitでイベントを通知する
つまり、$emit は単純に「値を直接送る」というより、
子がイベントを発生させ、そのイベントに付随する値を親に渡すものです。
たとえば、子コンポーネント側で次のように書くとします。
これは、「save というイベントが起きた」ということを親に知らせています。
さらに値も渡したいなら、次のように書けます。
この場合、親は save イベントを受け取りつつ、そのときのデータも一緒に受け取れます。
なぜ$emitが必要なのか
Vue.jsでは、コンポーネントを再利用可能に保つために、子コンポーネントが親の状態を直接書き換えない設計が推奨されます。
たとえば、子コンポーネントの中で親のデータを直接変更しようとすると、責務が曖昧になり、コードの見通しが悪くなります。
そのため、子は「こういう出来事が起きました」と親に伝えるだけにして、実際の状態管理は親が行うのが基本です。
この考え方には次のようなメリットがあります。
-
コンポーネントの責務が明確になる
-
再利用しやすくなる
-
データの流れがわかりやすくなる
-
デバッグしやすくなる
-
保守しやすくなる
つまり $emit は、Vue.jsらしい一方向データフローを守るための重要な仕組みです。
propsと$emitの違い
初心者が最初に混乱しやすいので、ここで整理しておきます。
props
親から子へデータを渡すための仕組みです。
子コンポーネント側では、props で受け取ります。
message: String
}
$emit
子から親へイベントを通知するための仕組みです。
親コンポーネントでは、そのイベントを受け取ります。
つまり、
-
親から子へ渡すのは props
-
子から親へ返すのは $emit
という役割分担になります。
最も基本的な$emitの使い方
まずは最小構成で見てみましょう。
子コンポーネント側
<button @click="sendMessage">親に通知する</button>
</template>
<script>
export default {
methods: {
sendMessage() {
this.$emit('notify')
}
}
}
</script>
この子コンポーネントでは、ボタンをクリックすると notify イベントを発火しています。
親コンポーネント側
<ChildComponent @notify="handleNotify" />
</template>
<script>
import ChildComponent from './ChildComponent.vue'
export default {
components: {
ChildComponent
},
methods: {
handleNotify() {
alert('子コンポーネントから通知を受け取りました')
}
}
}
</script>
親は @notify="handleNotify" と書くことで、子から発火された notify イベントを受け取っています。
$emitで値を渡す方法
イベントだけでなく、値も一緒に親へ渡したい場面は非常に多いです。
その場合は、$emit の第2引数以降にデータを指定します。
子コンポーネント側
<button @click="sendMessage">値を渡す</button>
</template>
<script>
export default {
methods: {
sendMessage() {
this.$emit('send-data', 'こんにちは、親コンポーネント')
}
}
}
</script>
親コンポーネント側
<ChildComponent @send-data="handleSendData" />
</template>
<script>
import ChildComponent from './ChildComponent.vue'
export default {
components: {
ChildComponent
},
methods: {
handleSendData(message) {
console.log(message)
}
}
}
</script>
この場合、親の handleSendData は、子から渡された 'こんにちは、親コンポーネント' を受け取れます。
フォーム入力値を親へ渡す例
$emit は、フォーム部品を自作するときによく使います。
子コンポーネント
<input type="text" @input="handleInput" />
</template>
<script>
export default {
methods: {
handleInput(event) {
this.$emit('input-change', event.target.value)
}
}
}
</script>
親コンポーネント
<div>
<ChildInput @input-change="updateValue" />
<p>入力された値: {{ inputValue }}</p>
</div>
</template>
<script>
import ChildInput from './ChildInput.vue'
export default {
components: {
ChildInput
},
data() {
return {
inputValue: ''
}
},
methods: {
updateValue(value) {
this.inputValue = value
}
}
}
</script>
このようにすれば、子コンポーネントで入力した値を親で受け取って表示できます。
複数の値を$emitで渡す方法
$emit では、複数の値を渡すこともできます。
子コンポーネント
親コンポーネント
handleUpdateUser(name, age) {
console.log(name)
console.log(age)
}
}
ただし、実務では複数の値をバラバラに渡すより、オブジェクトにまとめて渡すほうがわかりやすいことが多いです。
おすすめの書き方
name: '田中',
age: 30
})
親側では次のように受け取れます。
handleUpdateUser(user) {
console.log(user.name)
console.log(user.age)
}
}
この書き方のほうが可読性も高く、引数の順番ミスも防ぎやすくなります。
Si quieres conocer otros artículos parecidos a Vue.jsの$emit完全ガイド|親子コンポーネント間で値を渡す方法 puedes visitar la categoría Detakaiseki.
