In Vue.js, component communication plays a crucial role in building complex applications. It allows different components to interact with each other and share data or trigger actions. One way to achieve component communication is through the use of events. Events in Vue.js allow child components to emit custom events that can be listened to and handled by their parent components. In this topic, you will learn about component communication, emitting and listening events, and sending data with events.
Component communication
Component communication refers to the process of exchanging data or triggering actions between different components in a Vue.js application. There are various methods to achieve component communication, such as:
Props: allow parent components to pass data to child components through attributes.
Custom events: child components can emit events to notify parent components and pass data.
Vuex: provides a centralized state management solution for sharing data between components. You'll learn more about Vuex in upcoming topics.
Provide/Inject API: allows parent components to provide data and child components to inject and access that data.
Events are particularly useful when you want a child component to notify its parent about a specific action or state change.
To understand why component communication is crucial, let's look at a real-world example: let's say you are developing an e-commerce application. You can consider a shopping cart feature where multiple components are involved, such as a product listing component, a cart component, and a checkout component. Component communication is crucial in this scenario to ensure a seamless user experience. Here's how it can be applied:
Props: the product listing component receives product data from the server and passes it to child components to display the product details. For example, the product component might receive the product name, price, and image URL as props.
Custom events: when a user clicks the "Add to Cart" button in the product component, it emits a custom event to notify the cart component. The cart component listens for this event and updates its state to include the selected product.
Vuex: the cart component can use Vuex to manage the cart state centrally. Any component that needs access to the cart data can retrieve it from the store, ensuring consistency across the application.
Provide/Inject API: the checkout component might need access to the cart data. The cart component can use the provide/inject API to provide the cart data, and the checkout component can inject and use it without the need for explicit prop passing.
In this scenario, component communication enables the coordination between different components, allowing the user to browse products, add items to the cart, and proceed to checkout smoothly. It ensures data consistency, modularity, and reusability of components, enhancing the overall user experience.
Emitting events
To emit a custom event from a child component to its parent, you can use the defineEmits compiler macro to create an emit event. In its simple form, defineEmits will take an array of strings to name the events. defineEmits is available within the <script setup> with Composition API.
Here's an example of emitting an event from a child component:
<template>
<button @click="emitEvent">Click me</button>
</template>
<script setup>
const emit = defineEmits(['custom-event']);
function emitEvent() => {
emit('custom-event', 'Some data');
};
</script>In the example above, when the button is clicked, the emitEvent method is called, which emits a custom event named 'custom-event' and passes the string Some data as the payload.
You can also validate the emitted event's payload if you pass an object instead of an array of strings:
<script setup>
const emit = defineEmits({
// No validation
click: null,
// Validate submit event
submit: ({ email, password }) => {
if (email && password) {
return true
} else {
console.log('Missing email or password!')
return false
}
}
})
function submitForm(email, password) {
emit('submit', { email, password })
}
</script>Listening for events
To listen for custom events emitted by a child component, you can use the v-on directive (or its shorthand @) in the parent component's template. Here's an example:
<!-- ParentComponent.vue -->
<template>
<div>
<child-component @custom-event="handleEvent"></child-component>
<!-- or <child-component v-on:custom-event="handleEvent"></child-component> -->
</div>
</template>
<script setup>
import ChildComponent from './ChildComponent.vue';
function handleEvent(data) {
console.log('Received event:', data);
};
const components = {
ChildComponent: ChildComponent
};
</script>In the template section, we have a <div> element containing the child component, which is included using the <child-component> tag. We've also attached an event listener using @custom-event, which is bound to the handleEvent method in the parent component.
In the script section, we import the ChildComponent and define a method called handleEvent that takes data as a parameter. This method will be invoked when the custom event "custom-event" is emitted by the child component. In this example, the handleEvent method logs the received event and its data to the console.
In this script, the ChildComponent is explicitly registered using the components property within the setup function. By explicitly registering the component, you gain more control over the registration process and can customize the component's options if necessary. However, it's important to note that explicit registration is not always required, as Vue 3 can automatically detect and register components in some cases.
To sum up, the parent component listens for the "custom-event" emitted by the ChildComponent. When the event occurs, the handleEvent method is called, and it receives the emitted data as an argument. This mechanism enables communication between parent and child components in Vue.js.
You can emit and listen to multiple custom events in a Vue component.
Sending data with events
In addition to emitting events, child components can also send data along with the events. This allows the parent component to receive and utilize the data sent by the child. To pass data with an event, you simply include it as an argument when emitting the event. Here's an example:
<template>
<button @click="emitEvent">Click me</button>
</template>
<script setup>
const emit = defineEmits(['custom-event']);
function emitEvent() {
const data = {
message: 'Hello',
count: 10
};
emit('custom-event', data);
};
</script>In the example above, an object data is created with two properties: message and count. This object is then passed as the payload when emitting the 'custom-event' from the child component.
A complete example
In this example, clicking a button in a child component will emit a custom event, and a parent component will receive data and display it on the page. Here, we have a parent component called ParentComponent and a child component called ChildComponent:
<!-- ParentComponent.vue -->
<template>
<div>
<h2>Parent Component</h2>
<child-component @custom-event="handleEvent"></child-component>
<p>Received data: {{ eventData }}</p>
</div>
</template>
<script setup>
import ChildComponent from './ChildComponent.vue';
import { ref } from 'vue';
const eventData = ref('');
function handleEvent(data) {
eventData.value = data;
};
</script>The parent component listens for the 'custom-event' emitted by the child component using the @custom-event syntax. When the event is triggered, the handleEvent method in the parent component is called, and the emitted data is assigned to the eventData property.
The script uses the Composition API's ref function to create a reactive variable called eventData. This variable is used to store the data received from the child component.
In the parent component's template, we display the received data using {{ eventData }}.
<!-- ChildComponent.vue -->
<template>
<div>
<h3>Child Component</h3>
<button @click="emitEvent">Click me</button>
</div>
</template>
<script setup>
const emit = defineEmits(['custom-event']);
function emitEvent() {
const data = {
message: 'Hello',
count: 10
};
emit('custom-event', data);
};
</script>The child component has a button, and when it is clicked, it emits a custom event called 'custom-event' along with an object containing a message and a count.
When you run this example, clicking the button in the child component will emit the custom event, and the parent component will receive the data and display it on the page.
Conclusion
Emitting events in Vue.js provides a mechanism for component communication. It allows child components to notify their parents about specific actions or state changes. By emitting custom events and passing data along with them, you can create a flexible and reactive communication system between components in your Vue.js applications. In this topic, you've looked at component communication, emitting events, listening for events, and sending data with events.