Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a local event bus on Vue 3

Tags:

vue.js

vuejs3

how can I use the event bus on one page so that all components and the page can read and receive events there For example, in vue 2, I created an object which, when the page was created, assigned fields with the context and I used this context in all components of the page Example

//main.js
global.context = new Object();
global.context.app = Vue;

//field assignment with context
global.context.authorization = this;
 
//using context
global.context.authorization.$emit(
  "authorizationMessage",
  this.t("Password fields didn't match")
);

Can I use imports to improve this approach? In vue 3 I am getting error using

global.context.authorization.$on("authorizationMessage", (msg) => {
  alert(msg);
});
Uncaught (in promise) TypeError: global.context.authorization.$on is not a function
    at Proxy.created (Messenger.vue?1b1a:25)
    at callWithErrorHandling (runtime-core.esm-bundler.js?5c40:154)
    at callWithAsyncErrorHandling (runtime-core.esm-bundler.js?5c40:163)
    at callHookWithMixinAndExtends (runtime-core.esm-bundler.js?5c40:6032)
    at callSyncHook (runtime-core.esm-bundler.js?5c40:6018)
    at applyOptions (runtime-core.esm-bundler.js?5c40:5956)
    at finishComponentSetup (runtime-core.esm-bundler.js?5c40:6636)
    at setupStatefulComponent (runtime-core.esm-bundler.js?5c40:6567)
    at setupComponent (runtime-core.esm-bundler.js?5c40:6503)
    at mountComponent (runtime-core.esm-bundler.js?5c40:4206)
like image 727
Gorilka Avatar asked Jun 20 '21 14:06

Gorilka


People also ask

How do I use the Vue event bus?

The event bus is a special Vue instance that allows the passing of data from one component to another. It emits events in one component, then listens and reacts to the emitted event in another component without the help of its parent component.

How do I trigger an event at the Vue?

We can trigger events on an element with Vue. js by assigning a ref to the element we want to trigger events for. Then we can call methods on the element assigned to the ref to trigger the event.

How do you use the mitt at the Vue?

To add an event bus with Vue. js 3, we can use the mitt package. import { createApp } from "vue"; import App from "./App. vue"; import mitt from "mitt"; const emitter = mitt(); const app = createApp(App); app.


2 Answers

  1. There is no event bus in Vue 3. So $on will not work. See: https://v3.vuejs.org/guide/migration/events-api.html#events-api

  2. It is recommended that you create your event bus with external libraries, unless you want to make use of the supported parent-children event-based communication in which the child emits an event which can only be listened to by the parent. See: https://v3.vuejs.org/guide/component-custom-events.html#custom-events

  3. To implement an event bus for your application, make sure that you are emitting (firing) the events and listening to them with the same instance of the emitter. Else, it won't work.

  4. I preferred emittery (https://github.com/sindresorhus/emittery) for event bus with Vue js. It is robust with excellent Typescript support. I also use it on Node js via the Adonisjs framework.

  5. Create a useEvent hook //file: composables/useEvent.ts

import Emittery from 'emittery';
const emitter = new Emittery();
// Export the Emittery class and its instance.
// The `emitter` instance is more important for us here
export {emitter, Emittery};

// Export the Emittery class and its instance export { emitter, Emittery };

  1. In any vue component listen to an event // file: AnyVueComponent.vue
<script lang="ts">
import { defineComponent, onMounted } from 'vue';
import {emitter} from '../composables/useEvent'

export default defineComponent({
  name: 'ExampleComponent',
  components: {},
  props: {},
  setup() {
    onMounted(() => {
      emitter.on('event-name', async () => {
        // Perform actions. async...await is supported
      });
    })
    return {};
  },
});
</script>
  1. In any vue component emit the event
<script lang="ts">
import { defineComponent, onMounted } from 'vue';
import {emitter} from '../composables/useEvent'

export default defineComponent({
  name: 'ExampleComponent',
  components: {},
  props: {},
  setup() {
    void emitter.emit('event-name');
    return {};
  },
});
</script>
  1. Note that you can import the useEvent hook into any non-Vue file and it will work. It is just a JS/TS file.

For the Quasar Framework:

  1. Create a boot file
./node_modules/.bin/quasar new boot EventBus --format ts
  1. // file: EventBus.ts
import { boot } from 'quasar/wrappers';
import Emittery from 'emittery';

const emitter = new Emittery();

export default boot(({ app }) => {
  app.config.globalProperties.$event = emitter;
});

// Export the Emittery class and its instance
export { emitter, Emittery };
  1. Register with the quasar.conf.js file
module.exports = configure(function(/* ctx */){
  return {
    boot: [
      ...,
      'EventBus',
    ],
  }
}
  1. In any vue component listen to an event // file: AnyVueComponent.vue
<script lang="ts">
import { defineComponent, onMounted } from 'vue';
import {emitter} from '../boot/EventBus'

export default defineComponent({
  name: 'ExampleComponent',
  components: {},
  props: {},
  setup() {
    onMounted(() => {
      emitter.on('event-name', async () => {
        // Perform actions. async...await is supported
      });
    })
    return {};
  },
});
</script>
  1. In any vue component emit the event
<script lang="ts">
import { defineComponent, onMounted } from 'vue';
import {emitter} from '../boot/EventBus'

export default defineComponent({
  name: 'ExampleComponent',
  components: {},
  props: {},
  setup() {
    void emitter.emit('event-name');
    return {};
  },
});
</script>
like image 161
Ndianabasi Avatar answered Nov 15 '22 10:11

Ndianabasi


Following the Vue 3 migration guide for using Vue as an event bus, replace that bus with an instance of tiny-emitter:

// event-bus.js
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),
}

And use it like this:

// main.js
import eventBus from './event-bus'

//...
global.context.authorization = eventBus

demo

like image 39
tony19 Avatar answered Nov 15 '22 11:11

tony19