Vue event Emit vs Callback Props
Tags: vue
Published: 2023-04-11 04:40:58

---
title: Vue event Emit vs Callback Props
published: true
description: 
tags: vue
# cover_image: https://direct_url_to_image.jpg
# Use a ratio of 100:42 for best results.
# published_at: 2023-04-11 04:37 +0000
---

Emit events and Callback props will be compiled to the same code

## HTMLElement
[PlayGround](https://play.vuejs.org/#eNplj8GKwzAMRH9F+JSwkOxeu86yy/6GL6mrFFNHNrYcAiH/XiWlpaU3afSGGS3qL8ZmKqgOSmebXGTIyCWC7+ncGcXZqB9DAG6MITEskHCAFYYURjBKnEZtZxsoM8zQbffqs960oZBlFwgc2YR9xqoW/9xMvS8IHx18fe++4LHx4VzNNayGdHvrIamyMI7R94x7B31y0z4ALMu8Cixaexf1sTBL2iHQv3f2Iu3vwfJDTCHq9oa84L/2HcYJiZ9o3T56qPUKyJpppg==)

```vue
<button :onClick="increase">prop</button>
<button @click="increase">event</button>
```
```js
_createElementVNode("button", { onClick: increase }, "prop"),
_createElementVNode("button", { onClick: increase }, "event")
```

## Vue Component

[PlayGround](https://play.vuejs.org/#eNqlUUtugzAQvcrIK6NEkGyRST9R9z2AN5SYyirYFh5QJMTdO7YDTVupmy7H837zPLMn5/JpVKxkwjeDdghe4eigq817JRl6yU7SAOje2QFhhkG1sEA72B4kI6Zkd+uz7d26y4swBfEEaazxCFeoggQ/ZOGtHU2D2hrQphlU7RWfMvK45lPdjQp2FUywSCOKlI2S0ICqd12NKuaa5+tCCAARvUtrzp1uPij6KkkHuME62B1FTBRpCf3Y/MaqXiNhDxtYFJsh27P1pv8WltoIwTw1clGtNuo1TGKG2w0PJZ/KYwbVCSarL7CceCwtUWPOlflCQ2ByVUoWj5JsD8Q+ZOV38ta4Nc+YfDhVHlaQ4uSrfc6PkQLRi98Jk2xY/P0z4m1EJKOt5C/HW0WE8Z3FIsGLhP/R+PIJulDglg==)
```vue
<Comp :onClick="increase">prop +1</Comp>
<Comp @click="increase">emit +10</Comp>
```
```js
_createVNode(Comp, { onClick: increase }, { default: _withCtx(() => [ _createTextVNode("prop +1") ]), _: 1 /* STABLE */ }),
_createVNode(Comp, { onClick: increase }, { default: _withCtx(() => [ _createTextVNode("emit +10") ]), _: 1 /* STABLE */ })
```

## Combined
```vue
<button :onClick="increase" @click="increase">prop</button>
```
```js
_createElementVNode("button", { onClick: [increase, increase] }, "event")
```

# Drawback of Callback Props

## No `$event`

We cannot use `$event` in `:onClick`.

```vue
<button :onClick="increase($event.x)">prop</button> <!-- FAIL -->
```

Workaround is create anonymous callback but anonymous callback prop will not be cached and hurt performance. But this is easy to avoid.

[PlayGround](https://play.vuejs.org/#eNptj01uxCAMha9ioS4SVUra7RRGrXoNNil1RqgEEBiEFOXuJcn8SrOzn/09P8/sy/suJ2QHxqMK2hNEpOTBDPYkJKMo2VFaAD15FwhmCDjCAmNwE0hWScnWsXI2EhQQ67x5a1dtTFaRdha0VQGHiE0W8N5Wj9LlwSSEVwH5Y2Odwc64U1NaWKTl/Z6lXq4N4eTNQLjl4L86bwXAPJelLletv4j8JxHViwdnv41Wf/WDF8xoCcTxFmOXutLW33xwnvc79mDxqc4GT7GtvON4f03Jln8XtnRq)
```vue
<button :onClick="$event => increase($event.x)">prop</button> <!-- Workaround -->
<button @Click="increase($event.x)">prop</button>
```
```js
_createElementVNode("button", {
    onClick: $event => increase($event.x)
}, "prop", 8 /* PROPS */, _hoisted_1),
_createElementVNode("button", {
    onClick: _cache[0] || (_cache[0] = ($event) => (increase($event.x)))
}, "event")
```

In `v-for` context will not be cached and anonymouse callback will have the same performance with emit.
[Playground](https://play.vuejs.org/#eNpVj9tOhDAQhl9l0itI6rKeldCNxqcw1gvEos1C27QDQgiXvoVP55PsAHvI3rUz38z/zcCenVu1jWIpy0LhtUMIChsHVW6+hGQYJNtIA6BrZz3CAF6VMELpbQ2S0aRkU7uwJiB0AQS8rfklv+LX/Ibf8jt+zx/44/uJ6QmhHdE6nmplYwrU1kypr1EXU0C/avOqUYR1MEqTJYsXWdAHVe2qHNXslH3qFtqL0noy7UAbEpAM0q3qp8LeHGAYupE2Tc/so0GkuNSal0oXW+KiGMTmkE8zzluXJQs3L5B4mHoq9jMnWrXK4BlOIcHlhsTCt/2ZzYQQ0BP8//dL51Bz0U/If0mgK4+XsXEH+8uEEg==)
```vue
<div v-for="x in xs" :key="x">
    <button :onClick="() => setY(x)">prop</button>
  	<button @click="setY(x)">event</button>
</div>
```
```js
return (_openBlock(), _createElementBlock(_Fragment, null, _renderList(xs, (x) => {
    return _createElementVNode("div", { key: x }, [
        _createElementVNode("button", { onClick: () => setY(x) }, "prop", 8 /* PROPS */, _hoisted_1),
        _createElementVNode("button", { onClick: ($event) => (setY(x)) }, "event", 8 /* PROPS */, _hoisted_2),
    ])
}), 64 /* STABLE_FRAGMENT */))
```

## ~~Emit definition will shadow props definition~~

Not anymore.

# Pros of Callback Props

## Event tracing

With following tree ([PlayGround](https://play.vuejs.org/#eNqtlE2PmzAQhv/KyCeQKhAcEUFbRdwr9Yq0YomzRQvYMiZVhfjvnbEdAgkt1TbH+XpnPA/DyL5KGVwGzhKW9pWqpYae60FCU3bvh4LpvmBZ0QHUrRRKwwiKn2GCsxItFAwrC7YIH0Ur42swCI1J8japEl2voZLfdVl9wIGkPIww/xbkm7Hz0FW6Fh3gtK+NeD9Kr6c8H+dxcsGlbAaOhV7Hf0KulFB+YJJg2pLIbwq2598F0tBuB3eBhuatbErNzWbSH1F2LJvmjVKlErIHU5aGGDAJUvFsHN2g05SG5DARu69EdEcZ47bn5xUMXvjCk6MjnLvlbY2YtnrYp9xapOE8KvvCqNszYFtU9qkHOPFz3fFvZKUj0FMSz4dDBhdRn2DKvCVemvxaQs+gEo8nBUNpP1mXzMho7lcSRt3R9g2cuWbrEnOTR73wEyLhPYJvg9ZYThyauvrAVcwtcSOVg5uGNm9V81KtK5BURp0XyY8Qoief3Pri7g/uz6CiT5GKdlBFZnHRHSyyH2lRbm5Tr7xIfg/YieuybnoQklsc6OuHti3Vr8zIYrEzKVpoc2n20BwrN6W5tIUrJ0+YYQ31CV2jTYrmz/ZEitEao/lI/o1j/CmO8Q7H2GwovuNI9iNHys1t6pUjyf8vx3iTY2RBRg6bm9OQXPpycu2hnH4D32JWOg==)).
```html
<App>
    <Comp2        :onCp1 @e2>
        <Comp1    :onCp1 @e1>
            <Comp :onCp  @e >
```

On props callback stack, we can quick traced the `App_logCp`
is called by `Comp2_onCp2` which is called by it's children `Comp1_onCp1` which is then triggerd by `Comp_onCp`.

On emit, we only can traced `App_logE` 1 level down to `Comp2_onE2`.

In proper setup with source map like Vite, the `<anonymous>:27:48` will be replace with `App.vue`.

```
Callback props stack
Error
    at Proxy.App_logCp (<anonymous>:27:48)
    at Proxy.Comp2_onCp2 (<anonymous>:34:34)
    at Proxy.Comp1_onCp1 (<anonymous>:34:34)
    at Comp_onCp (<anonymous>:28:32)
    at callWithErrorHandling (https://play.vuejs.org/vue.runtime.esm-browser.js:1563:18)
    at callWithAsyncErrorHandling (https://play.vuejs.org/vue.runtime.esm-browser.js:1571:17)
    at HTMLButtonElement.invoker (https://play.vuejs.org/vue.runtime.esm-browser.js:9281:5)

Emit stack
Error
    at App_logE (<anonymous>:28:46)
    at callWithErrorHandling (https://play.vuejs.org/vue.runtime.esm-browser.js:1563:18)
    at callWithAsyncErrorHandling (https://play.vuejs.org/vue.runtime.esm-browser.js:1571:17)
    at emit (https://play.vuejs.org/vue.runtime.esm-browser.js:2065:5)
    at https://play.vuejs.org/vue.runtime.esm-browser.js:8710:45
    at Comp2_onE2 (<anonymous>:35:27)
    at callWithErrorHandling (https://play.vuejs.org/vue.runtime.esm-browser.js:1563:18)
    at callWithAsyncErrorHandling (https://play.vuejs.org/vue.runtime.esm-browser.js:1571:17)
    at emit (https://play.vuejs.org/vue.runtime.esm-browser.js:2065:5)
    at https://play.vuejs.org/vue.runtime.esm-browser.js:8710:45
```