Source code | NPM

Vue.js provides an API for dispatching events in components by this.$emit . But in functional components, you don't have this instance at all and many people who didn't previously worked with functional components, ask "How to emit an event in a functional component?"

The first solution is to use props for event listeners. It such a React way. The problem that in this case, you have strictly defined event name, can't use @ / v-on / v-model syntax and have some additional difficulties in implementing transparent wrappers. Example:



// Child component export default { name : ' base-input ' , functional : true , props : { onInput : { type : Function , default : () => (), }, }, render ( h , context ) { return ( < input onInput = { context . props . onInput } { ...{ attrs : context . data . attrs , on : context . listeners , } } /> ); }, };

<!-- Parent component template --> < template > <base-input onInput= "doSomething" /> </ template >

The second solution is to use context.listeners . This is a good way to dispatch an event in Vue.js. Example:



// Child component export default { name : ' base-input ' , functional : true , render ( h , context ) { return ( < input onInput = { e => context . listeners . input ( e . target . value ) } { ...{ attrs : context . data . attrs , on : context . listeners , } } /> ); }, };

<!-- Parent component template --> < template > <base-input @ input= "doSomething" /> </ template >

But there are some pitfalls when using context.listeners . I've found two situations when you will get TypeError: context.listeners.yourEvent is not a function

1. Listener can be undefined (not proveded)

If you don't pass a listener from the parent component, there is no handler for the event (input event in our case) in context.listeners object.

2. Listener value can be a function

The picture above shows the example structure of components and listeners. It this structure context.listeners.input in the C component will be an array of two functions: [doSomethingA, doSomethingB] . This is also true for this.$listeners .

So when using context.listeners (either directly calling handlers from this.$listeners ) you have to always check that listener exists and what type it has: Function or Array.

Using vue-emit

To solve above problems I've wrote the helper function that do all checks and provides the API similar to $emit . Thats how to use it:



yarn add vue-emit

import emit from ' vue-emit ' ; export default { name : ' base-input ' , functional : true , render ( h , context ) { return ( < input onInput = { e => emit ( context . listeners , ' input ' , e . target . value ) } /> ); }, };

The first argument is an object of listeners with eventName => handler structure. It is a standard Vue this.$listeners and context.listeners objects.

The second argument is an event name. Vue-emit will check listeners object and do nothing if handler is not defined or will call each handler if there are more than one listener.

You can also pass any amount of additional parameters and they all will be passed to handler. By the way, this is the use case with stateful components - when for some reason, you want to pass more than one argument to handler function as a payload.

Conclusion

I hope you will find this package useful and enjoyed reading this article. Feel free to ask your questions, open issues, pull request etc.

denisinvader / vue-emit Helper function for emitting events in Vue.js (functional) components Vue emit Helper function to emit events from Vue.js functional components. Can be used in regular components too CodeSandbox demo Installation yarn add vue-emit # or npm install vue-emit Usage import emit from 'vue-emit' ; export default { functional : true , render ( h , context ) { return ( < button onClick = { e => emit ( context . listeners , 'someEvent' , e , 'additional param' , 'etc' ) } > { context . children } < / button > ) ; } , } ; Params emit ( handlers_list , event_name , [ optional_payload ] ) ; handlers_list - object of functions. In Vue this is this.$listeners and context.listeners (for funtional components). Each value may be a function or an array of functions. In case of array emit will call all provided callbacks.

event_name - name of the event to fire. The event may not… View on GitHub

Photo by Daniele Riggi on Unsplash