Subscribe on changes!

Custom events should not be permeable

avatar
Jun 10th 2022

Additional scenario: When I use component components, I often register events that are not generic, but may listen for unintended actions

avatar
Jun 10th 2022

options 1

defineEmit on the "immediate" component (Comp). so vue does not attach a native event listener.

options 2

guard native event in the consumer level, (in case you don't have control over Comp)

function onChange(event) {
  if(event instanceof Event ) return 
  title.value = e.target.checked
}
avatar
Jun 10th 2022

The first sense is that the custom event is only applied to the current component and not triggered by the grandchild component due to the failure to declare defineEmit

<Comp @change="onChange" />

The change event should only be triggered by Comp emit('change')

This doesn't match the first intuition, you guys are talking about a user-side solution, what I'm thinking is why would vue do that?

avatar
Jun 10th 2022

I jumped to the workarounds to save you some time,

you can check the docs to better understand what is expected from vue when you bind events to a component with a defined emit and without, and what is the difference between native event, and vue emitted "events".

if you are trying to push a new feature or change of spec, I wish you good luck.

avatar
Jun 11th 2022

Thank you for your replies. @lidlanca @KaelWD

I'm here to talk about an application scenario

<component :is="hit" @change="onChange" />

const hit = Comp1 || Comp2 || Comp3

It may be that Comp2 does not need to respond to this event, but it happens that there are elements in Comp2 that do respond to the change event.

The user will find an unexpected response when handling onChange and will have to spend time to find the problem.

avatar
Jun 11th 2022

I agree that this specific scenario is an easy pitfall to introduce a bug.

However it's documented behavior that we could only change in a major release, as far as I can see right now. Though I'd be interested in suggestions

For now, what we can do is to better document this pitfall in the docs about <component>, so people are aware that they need to i.e. use a computed property to dynamically create an object with the right props and event listeners depending on the current component used in :is=.

We could also consider an eslint rule maybe?

avatar
Jun 12th 2022

Thank you for your answer. @LinusBorg

I think it could be described clearly in the <component> documentation that props and events should be calculated dynamically based on :is and not set in stone.

If you can add eslint rules that would be even better.

avatar
Jun 13th 2022

In Vue 2, custom vs. native event listeners are separated via the .native modifier.

In Vue 3:

  1. Listeners will capture both custom and native listeners if no emits or defineEmits are explicitly declared
  2. A listener will only capture custom events if it's declared as custom only via emits

Given that this is documented behavior, we cannot change how it works. It also means that when you attach an event listener to a component, you should not make the assumption that the event is only triggered by component custom events.

For the case discussed here - I think it's quite rare to attach an event listener on a dynamic component where not all possible components actually emit that event. When it happens, however, it could indeed be a pitfall. I'm not quite sure how Vue can change its behavior to avoid this without causing breaking changes.

avatar
Jun 13th 2022

I'm not quite sure how Vue can change its behavior to avoid this without causing breaking changes.

we can introduce modifiers to vue 3 (prefix).

The modifier can configure the type of binding ( native / emit ). additionally we can also introduce case sensitive modifier, that can solve https://github.com/vuejs/core/issues/5401 to escape the normalization and use event name as-is

to demonstrate the idea, we can look for a prefix that minimize possibility of breaking existing code:

  <!-- auto -->
  <div @Click=handler>1</div>
  
  <!-- auto + case sensitive -->
  <div @\Click=handler>2</div>
  
  <!-- emit only -->
  <div @@Click=handler>3</div>
  
  <!-- emit only + case sensitive -->
  <div @@\Click=handler>4</div>
  
  <!-- native only -->
  <div @^Click=handler>5</div>
  
  <!-- native + case sensitive -->
  <div @^\Click=handler>6</div>
avatar
Jun 14th 2022

Thank you for your replies. @lidlanca @KaelWD

I'm here to talk about an application scenario

<component :is="hit" @change="onChange" />

const hit = Comp1 || Comp2 || Comp3

It may be that Comp2 does not need to respond to this event, but it happens that there are elements in Comp2 that do respond to the change event.

The user will find an unexpected response when handling onChange and will have to spend time to find the problem.

add emits to Comp2 if does not need to respond to this event. will there be some problems?

avatar
Jun 18th 2022

@lidlanca Adding more modifiers to covers these cases would be thinkable in theory, though I'd be hesitant to add more shorthands as it will make the template more and more cryptic.

This should likely be discussed in an RFC: github.com/vuejs/rfcs

avatar
Jun 19th 2022

I actually started a discussion in RFC

https://github.com/vuejs/rfcs/discussions/451