Reputation: 12847
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
}
}
Upvotes: 11
Views: 18571
Reputation: 1398
Solution by @Dan will work, however in the case of typescript you might get 'emitter' is of type 'unknown'
error. Solution to this has been provided by @acantepie discussed here, the solution is to use singleton class like:
import mitt from "mitt";
export default mitt()
And use like:
import EventBus from "../lib/EventBus";
...
EventBus.emit(...)
EventBus.on(...)
...
Hope this helps someone like me :)
Upvotes: 0
Reputation: 36
In order to use Event Bus for Composition API you can do the following:
Install and register mitt
in your app.js like the TS did:
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);
After that we'll move the logic for accessing global emitter to a separate file accessEmitter.js
. I'll put it into js/Composables
folder:
import { getCurrentInstance } from 'vue';
export default function accessEmitter() {
return getCurrentInstance().appContext.config.globalProperties.emitter;
}
Now it can be utilized in your components:
<script setup>
import accessEmitter from '@/Composables/accessEmitter.js'
const emitter = accessEmitter();
// register listener
emitter.on("myEvent", (data) => {
console.log('my event');
});
// remove listener
emitter.off("myEvent");
</script>
Upvotes: 0
Reputation: 199
So far I have used this code to make the "emitter" available.
//main.ts
import mitt from 'mitt'
const emitter = mitt()
export default emitter
And then inside the components I use
import emitter from '@/main';
This worked so far in Vue2 and Vue3 - at least with the options API.
I have to admit though that I currently run into some trouble with the new vite server and the hot module reload (hmr). Is this style suboptimal in any way?
Upvotes: 3
Reputation: 63059
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
Upvotes: 36
Reputation: 35684
You may be able to use getCurrentInstance
to get the global property
component:
import { getCurrentInstance } from 'vue';
export default {
setup() {
// get current instance
const internalInstance = getCurrentInstance();
// get the emitter from the instance
const emitter = internalInstance.appContext.config.globalProperties.emitter;
}
}
Upvotes: 2