A Guide on How to use Emit in Vue
Tags: vue, javascript, webdev, tutorial
Published: 2022-05-09 17:06:23

In Vue, data is typically passed from parent components, to their children in a uni-directional fashion. This is transferred with [props](https://fjolt.com/article/vue-how-do-props-work), which are the properties or attributes we give to [components](https://fjolt.com/article/vue-using-components). 

For example, if we call a component `PageOne`, which has a prop called `name`, that `name` property would become available within the `PageOne` component itself, letting us do what we want to do with it. In that way, the data is passed down to the child component, when we declare it in a parent component or page:
![How Components work in Vue](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fe423n4amotwion1f5ea.png)
 

In most scenarios, props allow us to do everything we need to do with data. **Sometimes, however, we need to emit data upwards** - from a child component to its parent. For this, we use `$emit`, which lets us send data upwards, and then trigger an event in the parent component should an `$emit` event be fired.

## How $emit works in Vue
There are three ways to fire `$emit` in Vue, depending on if you're using the Options API, Composition API, or inlining your `$emit` events. If you are unsure, [you can read about the difference between the Composition API and Options API here](https://fjolt.com/article/vue-composition-api-vs-options-api). 
- `this.$emit` within the Options API.
- `$emit` if used in your HTML template.
- `defineEmits` and `emit` if used in the Composition API.

**Let's take a look at how this works, through a silly example**. Let's say we have a counter component, which looks like this:
```html
<template>
    <button @click="$emit('counterEvent')">Click Me</button>
</template>
```

This component is stored in a file called `Counter.vue`. Our component can't be changed as it's used in other places, but it does have an `$emit` event fired any time it is clicked. This is perfect, since we can use this in our parent component.

So what if we want to add this component somewhere - for example, in our `App.vue` file - and use it to display the value of our counter. Let's try doing that now:
```html
<template>
    <h1>{{ counter }}</h1>
  	<Counter @counter-event="incrCounter"/>
</template>

<script>
import Counter from './Counter.vue'
export default {
    // Add our components
  	components: {
      Counter
    },
    // Store our data
    data() {
        return {
            counter: 0
        }
    },
    methods: {
        incrCounter: function() {
            this.counter += 1;
        }
    }
}
</script>
```

Let's break this down - first of all, we include our `Counter`. Since it has an `$emit` event called `counterEvent`, we can attach that to our `Counter` HTML. Whenever `$emit` fires, it'll fire the `counterEvent`, and thus the function within that property. **Here, we run `incrCounter` any time `counterEvent` fires.**

By doing that, we also increase our `counter` data by 1, since that is what `incrCounter` does. As such, we've emitted the click event upwards to our parent component.

## Kebab Case

You may notice that when we defined our `$emit` event, we used camel case (`counterEvent`), but when tracking the event, we used kebab case (`counter-event`). 

In **Vue 3** it is fine to use `counterEvent` and `counter-event` interchangably since Vue 3 automatically converts `counterEvent` to `counter-event`. In **Vue 2**, this functionality does not exist, so just stick with `counter-event` for both. 

## Passing Data with $emit
Let's say instead, we want our component to define how much the `counterEvent` should increase by. If we want to do that, we can pass a second argument to the `$emit` function, which is the value:
```html
<template>
    <button @click="$emit('counterEvent', 2)">Click Me</button>
</template>
```

**Here**, we are passing the value `2` to our `counterEvent`. Let's go back to our `App.vue` file. To leverage this value in `counterEvent`, we need to write it as a function. Below, `n` is the value:
```html
<template>
    <h1>{{ counter }}</h1>
  	<Counter @counter-event="(n) => incrCounter(n)"/>
</template>

<script>
import Counter from './Counter.vue'
export default {
    // Add our components
  	components: {
      Counter
    },
    // Store our data
    data() {
        return {
            counter: 0
        }
    },
    methods: {
        incrCounter: function(value) {
            this.counter += value;
        }
    }
}
</script>
```

Now, our counter will increase by the value put in the child component, allowing us to pass data to our parent component as well. As you'd expect, this is not limited to just numbers, but can include any data structure - including objects and strings.

## Using $emit with the Options API
We've shown a quite simple example, but we could also have written our `Counter.vue` child component using a function instead. Here is an example with the **Options API**, using `this.$emit`:

```html
<template>
    <button @click="emitFunction">Click Me</button>
</template>

<script>
export default {
  emits: [ 'counterEvent' ],
 	methods: {
		emitFunction: function() {
		    this.$emit('counterEvent', 2)
        }
    }
}
</script>
```

This may prove to be a slightly cleaner way to use `$emit`, especially if you want to do other things along with using `$emit` whenever a button is clicked. 

### Adding your emit events to your prototype
You may note that we also defined our emit event in `emits` on the prototype. This is good practice for two reasons:
- **It lets you self-document the code** by showing which emit events are possible in this component.
- **It helps you keep track of deprecated emits**, since Vue will throw an error if an emit event is used but not found in the `emits` array.

## Using $emit with the Composition API
We can use `$emit` with the Composition API - the only difference is we have to use `defineEmits` instead. 

```html
<template>
    <button @click="emitFunction">Click Me</button>
</template>

<script setup>
import { defineEmits } from 'vue'

const emit = defineEmits(['counterEvent']);
const emitFunction = function() {
    emit('counterEvent', 2)
}
</script>
```

`defineEmits` is used to define a full list of all permissible `emit` events. Here, we only have one, `counterEvent`. If you had more than one, you could define them as so:
```javascript
const emit = defineEmits(['counterEvent', 'anotherEvent', 'finalEvent']);
```

If you use an emit event not listed in `defineEmits`, Vue will throw a warning, similar to using `emits` on the Options API. Otherwise, you can then use the `emit()` function to emit as usual, without needing to use the **Options API** at all.

## Final Thoughts and Best Practices

Emit is a powerful tool for sending data back up to the parent when we have to. It means datastreams can be two way in Vue. When defining `emit` code, the two main best practices are:
- Always define your emit events in either `emits` or `defineEmits`, which will help you keep your code clean and well documented
- Normal convention in Vue 3 is to use kebab case (`this-is-kebab-case`) for HTML, and camel case (`thisIsCamelCase`) in script. As such, it is best to follow this convention here too.

I hope you've enjoyed this guide on how `$emit` works. Stay tuned for more [Vue Content](https://fjolt.com/category/vue).