loading...

Renderless EventBus component for Vue.js

basitali profile image Basit Ali Mundia ・2 min read

Assumptions:

This article assumes you know about the neat little trick to use Vue as an event bus to communicate between your components. If not, read the article Creating a Global Event Bus with Vue.js by Joshua Bemenderfer.

Why?

I started off using the EventBus in my components and the implementation looked like this,

  mounted() {
    EventBus.$on('some-event', this.handleEvent)
  },
  destroyed() {
    EventBus.$off('some-event', this.handleEvent)
  }

This got a little cluttered as the number of events increased and the worse part? you can forget turning off the events.

Solution

The two solutions the came up to my mind were,

  1. Mixin to auto destroy events
  2. A dummy component that handles the mounted and destroyed logic.

Personally, I don't like mixins which is why I didn't even think twice about the point 1.

The dummy component seemed more fun to write. Additionally, event listeners in html templates looked a lot better than their JS counterpart (and it conforms to the idea behind https://vuejs.org/v2/guide/events.html#Why-Listeners-in-HTML).

This is how the component for EventBus looks like,

import _ from 'lodash'
import { EventBus } from '../common/eventBus.js'

export default {
  data() {
    return {
      events: Object.keys(this.$listeners),
      methods: _.mapValues(this.$listeners, (value, key) => this.handleEvent.bind(this, key))
    }
  },
  mounted() {
    this.events.forEach(event => {
      this.methods[event].SOMETHING = event
      EventBus.$on(event, this.methods[event])
    })
  },
  destroyed() {
    this.events.forEach(event => {
      EventBus.$off(event, this.methods[event])
    })
  },
  methods: {
    handleEvent(name, ...args) {
      this.$emit(name, ...args)
    }
  }
}

The demo is up at https://codesandbox.io/s/k5v2owk8v7.

Footnotes

This is my first ever post on any platform so looking forward to your comments.

Discussion

pic
Editor guide