When we are working will components, we feel the importance of passing data from child to parent component in Vue 3. With this, you can share information and display updated data across all components.
There are 2 ways to pass data from a child component to a parent component in Vue 3 composition API:
- Emit a custom event from the child component and listen to it from the parent.
- Pass a function to the child component as a prop and receive data as the function arguments.
Let's look into both of these methods with examples. You will also learn which method is the most recommended to use in your Vue 3 applications.
Pass Data From Child to Parent Component Using Emit
Vue has an official way to emit custom events from a component. If we emit an event, we also can send data with it. When the parent component listens to that event, the component will also have access to that data.
These are the steps to send data from a child to a parent component in Vue 3:
- Step 1: Use the
defineEmits()
method to register an event. It will return a function that you can call to emit that registered event. - Step 2: Listen to the event in a parent component using @ symbol followed by the same event name where you define that child component.
- Step 3: Provide a function while listening to the event. This function will run when the event gets fired. It will also get the data that comes with the event as the function argument.
Emitting a Custom Event From Child Component
In composition API, we can call the defineEmits()
method to register an event inside a component. When you call this method, it will return another function.
You can also apply this method and emit events to use a v-model
directive in a custom component in Vue 3.
Now you can call this function to emit any event that you have registered in the component. Here is an example for you.
// Todos.vue (Child component)
<template>
<h2>All Todos</h2>
<div>
<div v-for="todo in todos" :key="todo.id">
<span>{{ todo.task }}</span>
<button @click="emit('completeTodo', todo)">Done</button>
</div>
</div>
</template>
<script setup>
const props = defineProps(['todos']);
const emit = defineEmits(['completeTodo']);
</script>
I have a Todos.vue
component that accepts the todos
array as a prop and displays them. I want to modify a todo
object when a user clicks the button.
But we can't modify prop values because props are read-only properties.
This todos
array is present inside the parent component. To change anything in this array, you have to communicate from the Todos.vue
component to its parent component.
That's why I have registered the completeTodo
event in this component. When a user clicks the button, it will emit the event using emit()
and pass that specific todo
object with it.
You can learn more about the custom component events from the official documentation.
Now let's see how to listen to that event in the parent component and extract the data from it.
Also Read: Best Way to Re-render Vue 3 Components: Master Guide
Listening to The Custom Event in Parent Component
It is very easy to listen to a custom event. Because follow the same rules that we use for any other events. Use the event name in the <Todos />
component with the @
symbol.
// App.vue (Parent component)
<template>
<main>
<Todos :todos="todos" @complete-todo="updateTodos" />
</main>
</template>
<script setup>
import { ref } from 'vue';
import Todos from './components/Todos.vue';
const todos = ref([
{
id: 1,
task: 'Read Book',
isCompleted: false,
},
{
id: 2,
task: 'Work on project',
isCompleted: false,
},
{
id: 3,
task: 'Write new post',
isCompleted: false,
},
]);
const updateTodos = (updatedTodo) => {
todos.value = todos.value.map((todo) => {
if (todo.id === updatedTodo.id) {
todo.isCompleted = true;
}
return todo;
});
};
</script>
Here I am listening to the @complete-todo
event inside the App.vue
component. Whenever the child component fires this event, it will run the updateTodos
function in the App.vue
component.
This function will automatically receive the data as its argument that was passed with this event. Now you can find the updated todo
item from the todos
array and modify it.
That's how we can communicate with the parent component from a child component using custom events in Vue 3 composition API.
Also Read: Composition API VS Options API in Vue 3 For Beginners
Send Data From Child to Parent Component With Function Prop
You have a second way to exchange data from a child to a parent component in Vue 3 without emitting any event. In this case, we will only use props.
In the previous example, you have seen that the Todos.vue
component receives a todos
prop. This prop contains an array of tasks.
I will pass another prop along with the todos
prop. It will be a function. Instead of emitting an event, the child component can call this function.
// App.vue (Parent component)
<template>
<main>
<Todos :todos="todos" :complete-todo="updateTodos" />
</main>
</template>
<script setup>
import { ref } from 'vue';
import Todos from './components/Todos.vue';
const todos = ref([
{
id: 1,
task: 'Read Book',
isCompleted: false,
},
{
id: 2,
task: 'Work on project',
isCompleted: false,
},
{
id: 3,
task: 'Write new post',
isCompleted: false,
},
]);
const updateTodos = (updatedTodo) => {
todos.value = todos.value.map((todo) => {
if (todo.id === updatedTodo.id) {
todo.isCompleted = true;
}
return todo;
});
};
</script>
I am providing todos
and complete-todo
props to the <Todos />
component. The complete-todo
prop contains the updateTodos
function.
This function accepts one parameter which is the updated task. Whenever the child component will call this function with this parameter, it will update the todos
array in this component.
It is very simple. Now let's look into the child component and see how to use this prop function.
<template>
<h2>All Todos</h2>
<div>
<div v-for="todo in todos" :key="todo.id">
<span>{{ todo.task }}</span>
<button @click="completeTodo(todo)">Done</button>
</div>
</div>
</template>
<script setup>
const props = defineProps(['todos', 'completeTodo']);
</script>
I am receiving those 2 props in this component with the defineProps()
method. Whenever a user clicks on the button, execute the function from the prop and provide that specific todo object as its argument.
That's it. You can pass data from this child component to the parent in Vue 3 composition API using the prop function.
Also Read: Improve Performance in Vue 3 Using Lazy Loading and Dynamic Import
Conclusion
You have seen 2 ways to do the same thing. Both will work similarly. But which method should we use?
Recommendation: According to the official documentation, it is recommended to emit a custom event in order to pass data from a child to a parent component in Vue 3.
It's not compulsory that you have to emit an event to share data between components. You can follow any one of these methods. It's totally up to you.
But I personally like to use custom events because it is standard and also very easy to apply. I hope you will be able to pass the data from your child component to the parent component in Vue 3 applications.