We can use emit to emit some events in the parent component from the child component. This is highly useful when we want to update some state or call a method belonging to the parent component from the child component. However, we must pass the event-emitter from the parent to the child component to achieve the functionality.
We must be careful while updating states in parent components though. If we update some state which indirectly updates some other state in the child component as a return value, we might end up in an infinite loop.
Here’s an example, where we have a parent component that tells whether it’s Summer or Winter. We can then have a button placed in the child component to toggle between the seasons.
Call a method in the parent component from the child component
Here’s ParentComponent.vue file:
<script setup>
import { reactive } from 'vue';
import ChildComponent from './ChildComponent.vue';
let season = reactive({
isWinter: true
})
const toggleSeason = () => {
season.isWinter = !season.isWinter
}
</script>
<template>
<div>
<div :class="[
'season-text',
season.isWinter
? 'season-text-winter'
: 'season-text-summer'
]">
{{season.isWinter ? `? It's winter!` : `? It's summer!`}}
</div>
<ChildComponent @toggle-season="toggleSeason"/>
</div>
</template>
<style>
.season-text {
font-size: 40px;
}
.season-text-summer {
color:orange;
}
.season-text-winter {
color:blue;
}
</style>
Code language: HTML, XML (xml)
In the above code, we’ve passed an event-emitter to the child component at line 14. It’s worth noting that the standard way to name the event emitter for a method someMethod would be some-method=”someMethod”.
And here’s the ChildComponent.vue file:
<script setup>
const emit = defineEmits(['toggleSeason'])
</script>
<template>
<div>
<div class="season">
<h3>Change season</h3>
<button @click="$emit('toggleSeason')">Toggle Season</button>
</div>
</div>
</template>
<style>
.season {
border: 1px solid rgb(187, 187, 187);
margin: 24px;
padding: 24px;
}
</style>
Code language: HTML, XML (xml)
Then in the child component, we’ve defined emit functionality with the defineEmits() method. defineEmits() is a globally accessible method and we don’t need to import it to use it. We’ve then bound the $emit functionality with the toggle-season event emitter.
This is what the above code would look like in action:
Call a method with parameters in the parent component from the child component
Of course, not only can we call a method in the parent component. We can also pass values or arguments to the methods in the parent component from the child component. Let’s modify the above example so that we can enter some text values in the child component and have them displayed in the parent component:
Here’s the modified ParentCompoent.vue:
<script setup>
import { reactive } from 'vue';
import ChildComponent from './ChildComponent.vue';
let season = reactive({
emittedValues: 'winter'
})
const changeSeason = (emittedValues) => {
season.emittedValues = emittedValues ?? 'winter'
}
</script>
<template>
<div>
<div class="season-text">
? It's {{ season.emittedValues }}!
</div>
<ChildComponent @change-season="changeSeason"/>
</div>
</template>
<style>
.season-text {
font-size: 40px;
}
</style>
Code language: HTML, XML (xml)
As you can see, we now have a reactive state named season.emittedValues to show the season name received from the child component.
And here’s our ChildComponent.vue file content:
<script setup>
import { reactive } from 'vue';
const emit = defineEmits(['change-season'])
const seasonName = reactive({
value: null
})
</script>
<template>
<div>
<div class="season">
<h3>Change season</h3>
<input v-model="seasonName.value" />
<button @click="$emit('change-season', seasonName.value)">Change season</button>
</div>
</div>
</template>
<style>
.season {
border: 1px solid rgb(187, 187, 187);
margin: 24px;
padding: 24px;
}
</style>
Code language: HTML, XML (xml)
In the child component, we have a reactive state named seasonName.value to store the value of the user input. We then pass this value to the parent component using the emit event-emitter at line 15.
Here’s a little demo of the above code:
If you have any doubts or suggestions, sound off in the comments below!