While events in Javascript have been the “bread and butter” of many patterns and frameworks, Vue’s abstraction is simple and elegant. $emit was a revelation to me. One place that I leverage this frequently is for communication between my Container and Presentational components.

Let’s look at the typical todo example. This app has a list of items, and a header which will have the name of the list and a button to add a new item. This information is kept in a Vuex store. You could picture the container for this app looking something like this:

<template>

<section>

<todo-header

:title="title"

:add-item="handleAddItem"

/>

<todo-list

:items="items"

:mark-item-complete="handleItemComplete"

/>

</section>

</template> <script>

import { mapState } from 'vuex'; import TodoHeader from './TodoHeader';

import TodoList from './TodoList';

import {

UPDATE_TITLE,

ADD_ITEM,

MARK_ITEM_COMPLETE,

} from './mutation-types'; export default {

name: 'TodoWrapper',

computed: {

...mapState([

'title',

'items',

]),

},

methods: {

handleUpdateTitle(title) {

this.$store.commit(UPDATE_TITLE, title);

},

handleAddItem(item) {

this.$store.commit(ADD_ITEM, item);

},

handleItemComplete(item) {

this.$store.commit(MARK_ITEM_COMPLETE, item);

},

},

};

</script>

Let’s look at the TodoHeader :

<template>

<h1>{{ title }}</h1>

<input type="text" :v-model="newItem" />

<button @click="handleAddItem">Add item</button>

</template> <script>

export default {

name: 'TodoHeader',

data() {

return {

input: '',

};

},

props: {

title: {

type: String,

required: true,

},

addItem: {

type: Function,

required: true,

},

},

methods: {

handleAddItem() {

this.$props.addItem(this.$data.input);

},

},

};

</script>

As more functionality is added to the TodoHeader , (or the TodoList mentioned above), there will be more callback props defined similar to addItem . This will not only increase the amount of code, but will require additional stubbing in the unit tests. Events will help reduce this!

// ... props: {

title: {

type: String,

required: true,

},

},

methods: {

handleAddItem() {

this.$emit('add-item', this.$data.input);

},

},

}; // ...

Now, instead of passing add-item down as a prop, TodoWrapper will just listen for the event. We can do this with TodoList as well.

// ... <todo-header

:title="title"

@add-item="handleAddItem"

/>

<todo-list

:items="items"

@mark-item-complete="handleItemComplete"

/> // ...

This pattern will further decouple your presentational components from your containers, which will make your components more re-usable and reduce the amount of stubbing needed in your unit tests.