Parent-Child Component Communication
Passing Data with Props
In Vue 3, parent components can pass data to child components using props.
Defining Props in Child Components
Child components can declare their expected props using the defineProps function:
// UserProfile.vue
<template>
<div>{{ userName }}: {{ userAge }}</div>
<div>{{ userProfile.city }} {{ userProfile.gender }}</div>
<div v-for="(item, index) in contactList" :key="index">
{{ item.phone }}
</div>
</template>
<script lang="ts" setup>
interface Contact {
phone: string;
}
interface UserProps {
userName: string;
userAge: number;
}
const props = defineProps(['userName', 'userAge', 'userProfile', 'contactList']);
// Alternative approach with type definitions
const props = defineProps({
userName: {
type: String as PropType<string>,
default: () => ''
},
userAge: {
type: Number as PropType<number>,
default: () => 0
},
userProfile: {
type: Object,
default: () => ({})
},
contactList: {
type: Array as () => Contact[],
default: () => []
}
});
</script>
Passing Data from Parent Components
Parent components can pass data to child components by binding props to their template:
// App.vue
<template>
<UserProfile
:userName="userName"
:userAge="userAge"
:userProfile="userProfile"
:contactList="contactList">
</UserProfile>
</template>
<script lang="ts" setup>
import UserProfile from './components/UserProfile.vue';
const userName = ref('Alex');
const userAge = ref(28);
const userProfile = reactive({
city: 'New York',
gender: 'Male'
});
const contactList = ref([
{ phone: '1234567890' },
{ phone: '9876543210' }
]);
</script>
Child-to-Parent Communication with Events
Child components can communicate with parent components by emitting events.
Defining Events in Child Components
Child components can define custom events using defineEmits and trigger them with the emit function:
// UserProfile.vue
<template>
<div>{{ userName }}: {{ userAge }}</div>
<div>{{ userProfile.city }} {{ userProfile.gender }}</div>
<div v-for="(item, index) in contactList" :key="index">
{{ item.phone }}
</div>
<button @click="updateAge">Update Age</button>
<button @click="updateName">Update Name</button>
</template>
<script lang="ts" setup>
interface Contact {
phone: string;
}
const props = defineProps(['userName', 'userAge', 'userProfile', 'contactList']);
const emit = defineEmits(['ageUpdated', 'nameChanged']);
const updateAge = () => {
emit('ageUpdated', 35);
};
const updateName = () => {
emit('nameChanged', 'Jordan');
};
</script>
Handling Events in Parent Components
Parent components can listen to events emitted by child components and handle them accordingly:
// App.vue
<template>
<UserProfile
:userName="userName"
:userAge="userAge"
:userProfile="userProfile"
:contactList="contactList"
@age-updated="handleAgeUpdate"
@name-changed="handleNameChange">
</UserProfile>
</template>
<script lang="ts" setup>
import UserProfile from './components/UserProfile.vue';
const userName = ref('Alex');
const userAge = ref(28);
const userProfile = reactive({
city: 'New York',
gender: 'Male'
});
const contactList = ref([
{ phone: '1234567890' },
{ phone: '9876543210' }
]);
const handleAgeUpdate = (newAge: number) => {
userAge.value = newAge;
};
const handleNameChange = (newName: string) => {
userName.value = newName;
};
</script>
Cross-Component Communication with Provide/Inject
For communication between deeply nested components, Vue 3 provides the provide and inject APIs.
Providing Data from Ancestor Components
Ancestor components can provide data to all their descendants using the provide function:
// App.vue
<template>
<div>
<UserDashboard />
</div>
</template>
<script setup lang="ts">
import { ref, provide } from 'vue';
import UserDashboard from './components/UserDashboard.vue';
const contactList = ref([
{ phone: '1234567890' },
{ phone: '9876543210' }
]);
const removeContact = (index: number) => {
contactList.value.splice(index, 1);
};
const addContact = (contactInfo: { phone: string }) => {
contactList.value.push(contactInfo);
};
provide('contactData', {
contacts: contactList,
removeContact,
addContact
});
</script>
Injecting Data in Descendant Components
Descendant components can access the provided data using the inject function:
// ContactList.vue
<template>
<button @click="handleAdd">Add Contact</button>
<div v-for="(contact, index) in contacts" :key='index'>
<span>{{ contact.phone }}</span>
<button @click.prevent="handleRemove(index)">
Remove
</button>
</div>
</template>
<script setup lang="ts">
import { inject } from 'vue';
const { contacts, addContact, removeContact } = inject('contactData') || {
contacts: ref([]),
addContact: () => {},
removeContact: () => {}
};
const handleAdd = () => {
addContact({ phone: '5555555555' });
};
const handleRemove = (index: number) => {
removeContact(index);
};
</script>