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.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs