Concept Flow - Events for child to parent communication
Child Component
Parent Component
Parent updates state or reacts
The child sends an event with data upward, and the parent listens and reacts to it.
<template> <Child @notify="handleNotify" /> </template> <script setup> function handleNotify(message) { alert(message) } </script>
| Step | Action | Component | Event Emitted | Parent Listener | Parent Reaction |
|---|---|---|---|---|---|
| 1 | Child renders | Child | None | None | None |
| 2 | User clicks button in Child | Child | Emits 'notify' with 'Hello!' | Listens for 'notify' | Calls handleNotify('Hello!') |
| 3 | Parent handles event | Parent | None | Received 'notify' | Shows alert with 'Hello!' |
| 4 | Event cycle ends | Both | None | None | No further action |
| Variable | Start | After Step 2 | After Step 3 | Final |
|---|---|---|---|---|
| message | undefined | 'Hello!' | 'Hello!' | 'Hello!' |
| parentState | initial | initial | updated if any | updated if any |
Child emits event with data using $emit. Parent listens with @eventName in template. Parent handler receives data and updates state. This enables child-to-parent communication. Child cannot directly change parent data. Events flow upward only.
$emit to send a custom event to the parent, which listens for it.update?@eventName or v-on:eventName to listen to events. The handler should be a method reference without parentheses.<Child @update='handleUpdate' /> uses @update='handleUpdate' correctly without calling the method immediately.export default {
emits: ['send'],
methods: {
notify() {
this.$emit('send', 'hello')
}
}
}<Child @send='receiveMessage' />
notify() is called in the child?export default {
methods: {
sendData() {
this.emit('update', 123)
}
}
}$emit, not emit.emits is recommended, not declaring does not cause this error.save and cancel, each with a payload. How should you define and emit these events properly in Vue 3 Composition API <script setup>?defineEmits returns an emit function. It can accept an object to define event names and validators or an array of event names.const emit = defineEmits({ save: null, cancel: null })
function onSave() { emit('save', data) }
function onCancel() { emit('cancel', reason) } uses defineEmits({ save: null, cancel: null }) which is valid and recommended for typing events. Then emits events with emit('save', data) and emit('cancel', reason).defineEmits(['save', 'cancel'])
function onSave() { emit('save', data) }
function onCancel() { emit('cancel', reason) } calls defineEmits without assigning the result to emit, so emit is undefined. defineEmits(['save', 'cancel'])
const emit = defineEmits(['save', 'cancel'])
function onSave() { emit('save', data) }
function onCancel() { emit('cancel', reason) } calls defineEmits twice which is invalid. const emit = defineEmits(['save', 'cancel'])
function onSave() { this.$emit('save', data) }
function onCancel() { this.$emit('cancel', reason) } uses this.$emit which is not available in <script setup>.Pass the test and this pattern moves unknown