Event Bus
Replacing a Vue event emitter with a 3rd party library
Introduction
The Event Bus Pattern is quite common in Vue apps, even though the official recommendation is to avoid id due to the indirection in data flow.
Nonetheless, it was possible to use a simple unmounted Vue instance as a central event emitter, commonly called an event bus. In Vue 3, there's no Vue
constructor anymore, and the Event Emitter interface has been removed from the component instance API. If you are using an event bus in your app, you can replace it transparently with a tiny third-party package, though.
Then, in Vue 2
a globally shared event bus can be created in two lines in Vue 2. Your app does so in eventBus.js
.
import Vue from 'vue'
export default new Vue()
You can find a (dummy) usage of this event bus in ./views/Todos.vue
:
mounted() {
eventBus.$emit('ping')
},
Now, in Vue 3
Since Vue no longer provides an Event emitter interface of its own, we have ot use a 3rd party implementation. Many such event emitter packages can be found on npm - we will be using tiny-emitter because it's very small and provides the same interface as Vue 2 did, with the only exception that the methods don't start with $
, so eventBus.$on()
is tinyEmitter.on()
- but we can easily "translate that:
import emitter from 'tiny-emitter/instance'
export default {
$on: (...args) => emitter.on(...args),
$once: (...args) => emitter.once(...args),
$off: (...args) => emitter.off(...args),
$emit: (...args) => emitter.emit(...args),
}
Usage as a global property
Your app might have made the event emitter instance available to all components with something like this:
Vue.prototype = $eventBus = new Vue()
In that case, have a look at the previous chapter about Vue prototype extensions - it demonstrates how to do something similar in Vue 3.
Listening to a component's own events
In Vue 2, it was possible to use the event emitter interface to programmatically listen to a component's own emitted events, for example like this:
mounted() {
this.$on('closed', () => {
// do something when this component emits a 'close' event
// to its parent
})
}
This pattern is no longer available in Vue, and can't be replicated with a package like tiny-emitter
either. You will have to refactor your component to work without those event listeners.