What is the event bus in Vue.js?

Share

Vue.js is a library for building interactive web interfaces using component-based architecture. It provides several ways to allow communication between its components. One of them is the 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.

Syntax

// to emit the event
eventBus.$emit("event-name", data);

// to listen the event
eventBus.$on("event-name", callback);

// to destroy the event
eventBus.$off("event-name");

How to create an event bus

We can create the event bus inside our main.js file.

import Vue from 'vue'
import App from './App.vue'

export const eventBus = new Vue(); // creating an event bus.

new Vue({
  render: h => h(App),
}).$mount('#app')

Explanation

We created a new Vue instance that can handle communication between components without involving the parent component.

How to create two child components

Let’s create two components to see our event bus in action.

component1.vue:

<template>
  <div>
    <p>Age: {{ age }}</p>
  </div>
</template>

<script>
export default {
  props: ["age"],
};
</script>

<style lang="scss" scoped></style>

component2.vue:

<template>
  <div>
    <p>Age: {{ age }}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      age: 21,
    };
  },
};
</script>

<style scoped></style>

Explanation

The code snippet above creates a simple Vue component.

The template element contains the UI code. We used a single P element to display the age. The script element contains the logical code written in JavaScript. The style element contains the CSS code.

We used a single P element to display the age in both components. In component1.vue, we use the age variable as a prop. In component2.vue, we use the age variable as data.

How to set up events

Now that our components are ready, let’s set up the events. We will import the event bus in both the components and then emit an event from component2 and listen to that event in component1.

First, let’s emit an event from component2:

<template>
  <div>
    <p>Age: {{ age }}</p>
    <button @click.once="changeAge">Change Age</button>
  </div>
</template>

<script>
import { eventBus } from "../main";
export default {
  data() {
    return {
      age: 21,
    };
  },
  methods: {
    changeAge: function() {
      this.age = 42;
      eventBus.$emit("age-changed", this.age);
    },
  },
};
</script>

<style scoped></style>

Explanation

We added a button element that will call the changeAge method when clicked. The $once triggers a Vue method only once. When this button is clicked, the event listeners listening to age-changed will get triggered.

In the script, we imported the eventBus. We also created a method named changeAge that will change the value of the age variable and emit an event age-changed using $emit.

Now, let’s listen to the event in component2:

<template>
  <div>
    <p>Age: {{ age }}</p>
  </div>
</template>

<script>
import { eventBus } from "../main";
export default {
  props: ["age"],
  created: function() {
    eventBus.$on("age-changed", (data) => {
      this.age = data;   
      eventBus.$off("age-changed");
    });
  },
};
</script>

<style lang="scss" scoped></style>

Explanation

In the script, we imported the eventBus. In the created lifecycle hook, we added an event listener of ‘age-changed’ using $on.

When this event gets triggered, it accepts an object as an argument that contains information about what was changed.

At the end of the function, we destroyed the event using $off.

Conclusion

With this, the components are now ready to communicate via an event bus. The event bus is cleaner, involves less code, and provides an efficient way to achieve independent communication between components.

Avoid using the event bus for large applications and stick with the props down, events up method. Vue will warn you in the console if you use it.

This shot is specific for Vue2 only. $on, $off, and $once have been removed in Vue3.