old-docs-site icon indicating copy to clipboard operation
old-docs-site copied to clipboard

[2.0-preview] Docs note: Could use fleshing out of how dispatching de-sugared events in 2.0

Open tjsavage opened this issue 7 years ago • 6 comments

From @tjsavage on December 8, 2016 19:59

With #UseThePlatform and removing some of the sugaring around dispatching events, there are now some gaps in 2.0 that can make managing custom events harder to figure out - especially with how events bubble and behave across shadow roots. This can be fixed with documentation, perhaps on the README in the short-term (before launch).

Particularly - this.fire and listeners block helped a lot with event handling. Can we explain how to get to "sensible defaults" with lower-level event firing? e.g. "You want to do X with your event => Here's how you set it up"?

Copied from original issue: Polymer/polymer#4207

tjsavage avatar Dec 08 '16 20:12 tjsavage

@tjsavage @arthurevans I would like to help with this but need someone's brains to pick. Can you recommend anyone on the Polymer team I can ask?

ghost avatar Apr 07 '17 02:04 ghost

I believe @kevinpschaaf mentioned this to me originally

tjsavage avatar Apr 07 '17 18:04 tjsavage

Thanks @tjsavage, I will follow up with @kevinpschaaf.

ghost avatar Apr 10 '17 05:04 ghost

I think the two main use cases for firing events are:

  1. I want to fire a non-bubbling event (only my host can listen, by adding listener directly on me):

    this.dispatchEvent(new CustomEvent('my-event'));
    
  2. I want to fire a bubbling event that anyone all the way up the tree can see (what fire did by default):

    this.dispatchEvent(new CustomEvent('my-event', {bubbles: true, composed: true}));
    

The new thing in ShadowDOM v1 is the ability to fire a bubbling event that stops at the nearest shadow root ("Use Case 3"). This means any light dom parent all the way up to the shadowRoot can catch the event via delegation, but nothing outside of the shadow root including the host element.

this.dispatchEvent(new CustomEvent('my-event', {bubbles: true}));

Since this is new and we've lived with (1) and (2) for so long, it's hard to come up with critical use cases where you need this capability. However, I hesitate to say it's not useful. It's just a thing you can do now, a tool in the toolbox that might prove useful. But I don't think we can give concrete guidance on when to use 2 vs. 3 yet.


As for the listening side, the only thing affected by any of this is that events fired per (3) ({bubbles: true, composed: false}) within a host's shadow root can only be caught on children of the shadowRoot or on the shadowRoot itself (in v1 shadowRoot now has an addEventListener interface for this purpose; in v0 it didn't). What this means is that a host should do this.shadowRoot.addEventListener to catch a bubbling but non-composing event coming up from its shadow children, since it won't fire on the host element itself (composed: false means it stops at the shadowRoot).

Other than that, not much else is affected on the listening side. The direct replacement for listeners: { event: handler } is just this.addEventListener('event', e=>this.handler(e)), and its generally safe to do this from the constructor. However, a main reason we removed listeners as sugar is that we don't want to decide when in the element's lifecycle we add the listener (because adding listeners is startup work that can have cost). Instead, we want the author to decide when to add the listener by writing that code at the appropriate spot for their element.

Particularly, there is generally no reason to add UI event listeners (click, mousemove) prior to first paint, since it's impossible for those events to be generated from the user before pixels have drawn on the screen. So for a large class of events, it's better to do Polymer.RenderStatus.afterNextRender(()=>this.addEventListener('event', e=>this.handler(e))) from e.g. constructor so that the work to add the event doesn't block the critical first paint. However, other patterns like building a list of children based on them firing events as they are created requires adding the listener early (e.g. synchronously in constructor). So we'd just like users to consider when the listener is needed and add it at the appropriate time.

kevinpschaaf avatar Apr 10 '17 17:04 kevinpschaaf

Are there any performance benefits to using:

this.dispatchEvent(new Event('my-event'));

VS

this.dispatchEvent(new CustomEvent('my-event'));

when not passing data through detail?

jsilvermist avatar Apr 10 '17 17:04 jsilvermist

Thanks @kevinpschaaf. Some of this is currently covered in https://www.polymer-project.org/2.0/docs/devguide/events#custom-events but we can do a better job of giving prescriptive advice on where to add event listeners, and why.

arthurevans avatar Apr 10 '17 23:04 arthurevans