JAVASCRIPT
Implementing a Global Event Bus with Vue 3 and `mitt`
Establish a robust global event bus in Vue 3 using the `mitt` library for cross-component communication, enabling loose coupling without prop drilling or direct parent/child relations.
// src/plugins/eventBus.js
import mitt from 'mitt';
const emitter = mitt();
export const useEventBus = () => {
return {
emit: emitter.emit,
on: emitter.on,
off: emitter.off
};
};
// main.js (or wherever your app is initialized)
// import { createApp } from 'vue';
// import App from './App.vue';
// import { useEventBus } from './plugins/eventBus'; // Ensure this is not directly used for global access via app.config.globalProperties for cleaner setup.
// const app = createApp(App);
// app.config.globalProperties.$eventBus = useEventBus(); // This is one way, but a composable is cleaner for Vue 3.
// app.mount('#app');
// src/components/ComponentA.vue (Emitting component)
<template>
<div style="border: 1px solid red; padding: 10px; margin-bottom: 10px;">
<h3>Component A (Emitter)</h3>
<button @click="sendMessage">Send Message to B</button>
</div>
</template>
<script setup>
import { useEventBus } from '@/plugins/eventBus';
const { emit } = useEventBus();
const sendMessage = () => {
const message = `Hello from Component A at ${new Date().toLocaleTimeString()}`;
emit('custom-message', message);
console.log('Component A emitted:', message);
};
</script>
// src/components/ComponentB.vue (Listening component)
<template>
<div style="border: 1px solid blue; padding: 10px;">
<h3>Component B (Listener)</h3>
<p v-if="receivedMessage">Received: {{ receivedMessage }}</p>
<p v-else>Waiting for messages...</p>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
import { useEventBus } from '@/plugins/eventBus';
const { on, off } = useEventBus();
const receivedMessage = ref('');
const handleCustomMessage = (payload) => {
receivedMessage.value = payload;
};
onMounted(() => {
on('custom-message', handleCustomMessage);
console.log('Component B mounted, listening for custom-message.');
});
onUnmounted(() => {
off('custom-message', handleCustomMessage);
console.log('Component B unmounted, stopped listening.');
});
</script>
// src/App.vue
<template>
<div>
<h1>Event Bus Example</h1>
<ComponentA />
<ComponentB />
</div>
</template>
<script setup>
import ComponentA from './components/ComponentA.vue';
import ComponentB from './components/ComponentB.vue';
</script>
How it works: While prop drilling and global state management libraries (like Pinia) are often preferred, a global event bus using a lightweight library like `mitt` can be invaluable for loosely coupled communication between distant or unrelated Vue components. This snippet sets up a `useEventBus` composable that encapsulates `mitt`'s `emit`, `on`, and `off` methods. Components can then easily send messages (emit events) and listen for them (on events) without direct hierarchical relationships, simplifying communication for certain scenarios. It's crucial to `off` listeners in `onUnmounted` to prevent memory leaks.