How to Pass Data From Child to Parent in Vue 3 (Composition API)

Robin
Updated on March 7, 2024

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 it. 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

You have seen 2 ways to do the same thing. Both will work similarly. But which method should we use?

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.

Related Posts