5

I have migrated my application to Vue 3.

Now my linter shows a deprecation error, documented here: https://eslint.vuejs.org/rules/no-deprecated-events-api.html.

The documentation shows how to replace this.$emit with the mitt library, but it doesn't show how to replace this.$parent.$emit.

tony19
  • 125,647
  • 18
  • 229
  • 307
mdziedzinski
  • 55
  • 1
  • 1
  • 7
  • did you migrate your application from Vue 2? – Abhay Kumar Jun 01 '20 at 06:03
  • Yes, I am migrating from Vue 2 – mdziedzinski Jun 01 '20 at 06:36
  • 2
    In Vue 3, $on, $off and $once instance methods were removed. You will no longer be able to implement the event emitter interface using an eventHub for example. You will however be able to continue using $emit as it will remain part of the existing API as it's used to trigger event handlers declaratively attached by a parent component. – Soupedenuit Sep 03 '20 at 17:15

4 Answers4

17

In your child component:

setup(props, { emit }) {
   ...
   emit('yourEvent', yourDataIfYouHaveAny);
}

Your parent component:

<your-child @yourEvent="onYourEvent" />

...

onYourEvent(yourDataIfYouHaveAny) {
  ...
}
Adam Reis
  • 4,165
  • 1
  • 44
  • 35
Developer
  • 194
  • 2
  • 4
5

With script setup syntax, you can do:

<script setup>
    const emit = defineEmits(['close', 'test'])
    
    const handleClose = () => {
        emit('close')
        emit('test', { anything: 'yes' })
    }
</script>

No need to import anything from 'vue'. defineEmits is included.

Read more here: https://learnvue.co/2020/01/4-vue3-composition-api-tips-you-should-know/

agm1984
  • 15,500
  • 6
  • 89
  • 113
1

Due to the composition api, it allows you to use the $attrs inherited in each component to now fulfill this need.

I assume that you are using this.$parent.emit because you know the the child will always be part of the same parent. How do I simulate the above behavior with $attrs?

Lets say I have a table containing row components. However I wish to respond to row clicks in table's parent.

Table Definition

 <template>
  <row v-bind="$attrs" ></row>
 </template>

Row Definition

<template name="row" :item="row" @click=onClick(row)>
  Your Row 
</template>

export default {
    emits: {
      row_clicked: () =>{
       return true
      }
   }, 
   onClick(rowData){
     this.$emit('row_clicked',rowData)
  }
}

Finally, a component containing your table definition, where you have a method to handle the click.

<table
@row_clicked=clicked() 
>

</table

Your table component should effectively apply @row_clicked to the row component thus triggering when row emits the event.

MooCow
  • 1,397
  • 1
  • 12
  • 30
0

There is similar way of doing it by using the context argument that is passed in second argument inside the child component (the one that will emit the event)

setup(props, context){
     context.emit('myEventName')
}

...then emit it by calling the context.emit method within the setup method.

In your parent component you can listen to it using the handler like so:

<MyParentComponent @myEventName="handleMyEventName" />

Of course, in the setup method of the MyParentComponent component you can declare the handler like this

//within <script> tag of MyParentComponent
setup(props){
    const handleMyEventName() => {
            ...
    }
    return { handleMyEventName }
}
luigi7up
  • 5,779
  • 2
  • 48
  • 58