Skip to content

Instantly share code, notes, and snippets.

@rexpan
Created April 11, 2023 04:24
Show Gist options
  • Select an option

  • Save rexpan/7519f4201597934c8626b32921dbe4bc to your computer and use it in GitHub Desktop.

Select an option

Save rexpan/7519f4201597934c8626b32921dbe4bc to your computer and use it in GitHub Desktop.
Emit events vs Callback Props

Emit events vs Callback Props

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

HTMLElement

PlayGround

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

Vue Component

PlayGround

<Comp :onClick="increase">prop +1</Comp>
<Comp @click="increase">emit +10</Comp>
_createVNode(Comp, { onClick: increase }, { default: _withCtx(() => [ _createTextVNode("prop +1") ]), _: 1 /* STABLE */ }),
_createVNode(Comp, { onClick: increase }, { default: _withCtx(() => [ _createTextVNode("emit +10") ]), _: 1 /* STABLE */ })

Combined

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

Drawback of Callback Props

No $event

We cannot use $event in :onClick.

<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

<button :onClick="$event => increase($event.x)">prop</button> <!-- Workaround -->
<button @Click="increase($event.x)">prop</button>
_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

<div v-for="x in xs" :key="x">
    <button :onClick="() => setY(x)">prop</button>
  	<button @click="setY(x)">event</button>
</div>
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).

<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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment