javascriptvue.jsvuejs3event-busvue-composition-api

Vue 3 Event Bus with Composition API


I have setup mitt and trying to dispatch event to another component but I am having hard time because in the setup() method it doesn't have this for accessing app instance.

Here is what I tried:

import App from './App.vue'
const el = document.getElementById('app')

import mitt from 'mitt';
const emitter = mitt();

const app = createApp(App)
app.config.globalProperties.emitter = emitter;
app.mount(el);

And in the component, I want to dispatch an event

export default {
   setup() {
      function toggleSidebar() {
          this.emitter.emit('toggle-sidebar');

          console.log(this); // binds to setup(), not the vue instance.
      }
   }
}

As this doesn't exist, I can't access the .emitter. What am I missing? How to use officially suggested mitt in Vue 3 composition api?


By the way if I use the v2 syntax, I can access this.emitter. But I am curious about Composition API way

export default {
  mounted() {
    console.log(this.emitter); // works
  }
} 

Solution

  • To use an event bus in Vue 3 Composition API, use Vue 3's new provide api in main.js, and then inject in any component:

    1. Install mitt:

    npm install mitt
    

    2. Provide:

    main.js

    import { createApp } from 'vue';
    import App from './App.vue';
    
    import mitt from 'mitt';                  // Import mitt
    const emitter = mitt();                   // Initialize mitt
    
    const app = createApp(App);
    app.provide('emitter', emitter);          // ✅ Provide as `emitter`
    app.mount('#app');
    

    3. Inject

    3a. Any Component - Emit an event

    import { inject } from 'vue'
    
    export default {
      setup() {
        const emitter = inject('emitter'); // Inject `emitter`
        const mymethod = () => {
          emitter.emit('myevent', 100);
        };
        return {
          mymethod
        }
      }
    }
    

    Call mymethod from a button click or something.

    3b. Any Component - Listen for the event

    import { inject } from 'vue'
    
    export default {
      setup() {
        const emitter = inject('emitter');   // Inject `emitter`
    
        emitter.on('myevent', (value) => {   // *Listen* for event
          console.log('myevent received!', `value: ${value}`);
        });
      },
    }
    

    Console

    myevent received! value: 100