DEV Community

Cover image for Vue3 event emitter
deexter
deexter

Posted on • Updated on

Vue3 event emitter

I recently have been asked to make micro-frontend with webpack plugin Module federation
This micro-frontend used vuex library before, but it was used only for opening/closing modals.

So we tended to replace it with something more simple.
Among our candidates was mitt, which is very tiny library.

import mitt from "mitt";
export const emitter = mitt();
Enter fullscreen mode Exit fullscreen mode

Our first try was register emitter in mounted lifecycle method.

export default defineComponent({
...
  mounted() {   
    this.emitter.on("open-modal", name => { 
      this.shouldDisplay = name === ModalType.ThankYou; 
    }); 
  },
...
Enter fullscreen mode Exit fullscreen mode

This works only if you use emitter in another component, but if you want emit outside of vue component, it does not work.
This is probably caused, because you have to have instance of Vue app and if you use recommended getcurrentinstance you get null outside of vue components.

If you want to use it like we do, with hooks

import {emitter} from "../utils/emitter";

export const useModal = () => {
  const openModal = (name: string) => {
    emitter.emit('open-modal', name)
  }
  const closeModal = () => {
    emitter.emit('open-modal', '')
  }
  return { openModal, closeModal };
}
Enter fullscreen mode Exit fullscreen mode

You have to register event listener also with hook

<template>
  <Modal :isOpen="shouldDisplay" @close-modal="closeModal">
...
  </Modal>
</template>

<script lang="ts">
...
export default defineComponent({
  name: "CustomModal",
  components: {
    Modal,
  },
  setup() {
    const {closeModal} = useModal();
    onMounted(() => {
      emitter.on("open-modal", name => {
        shouldDisplay.value = name === ModalType.ThankYou;
      })
    })
    return {
      closeModal,
      shouldDisplay,
    };
  }
});
</script>
Enter fullscreen mode Exit fullscreen mode

Do you have also experience with event emitter?
Share your ideas.

Discussion (2)

Collapse
jackzhoumine profile image
jackzhoumine

hello , I have a question, How to listener lifecycle hook in vue3 like vue2?
vue 2

  mounted() {
    const onResize = () => {
      console.log('onResize')
    }
    window.addEventListener('resize', onResize)
    // hook:liefHook
    this.$once('hook:beforeDestroy', () => {
      window.removeEventListener('resize', onResize)
    })
  }
Enter fullscreen mode Exit fullscreen mode

vue3 does not support this.$once anymore. I use npm to do this according to offical docs and lifecyle hook event.

onMounted(() => {
  console.log('vue3 mounted')
  function onResize() {
    console.log('onResize')
  }
  window.addEventListener('resize', onResize)
  event.once('vnode-before-unmount', () => {
    console.log('vnode-before-unmount')
    removeEventListener('resize', onResize)
  })
})
Enter fullscreen mode Exit fullscreen mode

event:

import emitter from 'tiny-emitter/instance'

export const event = {
  emit: (...args) => emitter.emit(...args),
  on: (...args) => emitter.on(...args),
  off: (...args) => emitter.off(...args),
  once: (...args) => emitter.once(...args),
}
Enter fullscreen mode Exit fullscreen mode

but event.once does not call when component umount.
Could u give me some advices? thinks

Collapse
deexter profile image
deexter Author • Edited on

Try onUnmount hook