Event handling done right

Stavros Droutsas
ITNEXT
Published in
3 min readJun 17, 2023

--

This is a trap that I have fallen into numerous times. In modern frontend frameworks there are a ton of parent and child components. The parent component passes data using props and child components emit events to communicate with their parent. Or not?

Of course the parent should provide data using props but there are cases where the parent should also provide handler functions instead of reacting to the emitted event. Let’s elaborate.

Welcome the test subjects

To start the investigation we need a simple child component in two variations. One that emits an event to its parent and one that accepts a handler function as a prop.

As you can see above, the main difference is in line 13 (both gists). On the first variation the component emits an event, but on the second the component is executing the passed function.

Start the comparison

The comparison will cover the following aspects

  • Child component complexity/verbosity
  • Parent component complexity/verbosity
  • Unit testing
  • App performance

Complexity of child components

Both components are even and look simple. Complexity and verbosity are kept low and it’s easy to understand with a glimpse. Score for button emit VS button handler is 1–1.

Complexity of parent components

Both parent components have the same function. The only difference is noticeable in line 3, where there is the event handler on the first and the prop on the second. Once again the complexity and verbosity are low. The tie remains, score is 2–2.

Unit testing

The tests of the child components:

Regarding the above unit tests the emitted event case is a bit simpler. In general there are equivalent but if we want to be precise, we have to address the extra step of the jest function definition. So the score is 3–2 and the emit variation takes the lead.

The tests of the parent components:

Regarding the above tests, we have to follow the same steps until the mount of the parent components. On the emit case, we have to force the child component to emit an event and with the help of a spy, check if the corresponding function is called. On the handler case we have to populate the stubbed child with a props field and then check if the new prop is the expected. I cannot determine which is simpler. Another tie. Score is 4–3.

Performance

Before checking the results it’s time to think about the differences of the components. On the first case the child component emits a custom event, its parent listens and executes a function. This type of event binding is probably implemented using the Observer pattern. It does not add an additional event listener, because it’s not a DOM event. On the second case, the child component needs an additional prop. Props have reactivity which is implemented using a Proxy object.

So, which is more expensive? Let’s add one magic line in both parent components to find out:

v-for="i in 300_000" :key="i"

Then we have to create a production build of the application and host it with NGINX or Live Server. Open an incognito window, without any extensions, open dev tools and check the performance monitor:

emit custom event
use function as a prop

We can see that in both cases we have ~300,000 event listeners and ~1,200,000 DOM nodes. (The results are after the garbage collection). There is a noticeable difference in JS heap size of ~100 MB in favor of the handler variation. After the performance results, the handler variation wins by knock-out.

Even though I personally prefer emitting custom events, because I like the separation of passing data with props and react to emitting events with functions, this difference is enough for me to stick with the second approach and skip the custom events as much as possible.

You can find the code here

Enjoy 🚀🚀🚀

--

--

Frontend developer specialized in Angular and Docker Container enthusiast. Intrigued with Reactive Programming, clean code practices and problem solving.