Let's say an Outer component contains an Inner component, and we want an event from the Inner component to be propagated to the Outer component. Without using the store, there are 2 ways to do this:
Inner.svelte: Use Svelte's dispatcher to dispatch a repackaged version of the original event:
<input type="text" on:input={callDispatcher} />
const dispatcher = createEventDispatcher();
function callDispatcher(e) {
dispatcher("mymsg", {
foo: e.target.value
});
}
Outer.svelte: Listen for Inner's dispatched event:
<Inner on:mymsg={handler} />
function handler(e) {
alert(e.detail.foo);
}
Inner.svelte: Accepts handler passed in by Outer:
export let externalHandler;
<input type="text" on:input={externalHandler} />
Outer.svelte: When Inner event of interest occurs, it will call Outer's handler:
<Inner externalHandler={handler} />
function handler(e) {
alert(e.target.value);
}
Which one is a better practice? Method 1's dispatcher seems to be an unnecessary middle-layer that not only adds more code but also loses the original event information. But strangely, the Svelte tutorial mentions Method 1 instead of Method 2.
There is no real difference and you can indeed use both. However, method 2 will not work for native elements, leaving you with a mix of both approaches and you get cod like this:
<Child clickHandler="{childClick}" />
<button on:click="{buttonClick}">click</button>
You would always have to remember when to use which one, while if you use the dispatcher method this will always be the same
<Child on:click="{childClick}" />
<button on:click="{buttonClick}">click</button>
The extra dispatcher code is a trade-off in this.
I find using function prop much simpler, more idiomatic, and does the job elegantly most of the time for me.
<!-- App.svelte -->
<Button onClick={handleClick}></Button>
<!-- Button.svelte -->
<button on:click={onClick}>
Click me
</button>
The only case I use event forwarding is when I need to do... well... event forwarding. :) (from deeply nested component)
<!-- App.svelte -->
<Outer on:customEvent={handleCustomEvent} />
<!-- Outer.svelte -->
<Inner on:customEvent />
<!-- Inner.svelte -->
<Button on:customEvent />
<!-- Button.svelte -->
<button on:click={() => dispatch('customEvent')}>
Click me
</button>
Reference: https://www.donielsmith.com/blog/2020-04-21-props-vs-event-dispatcher-svelte-3/
Disclaimer: I'm new to Svelte, coming from React. 🥳
Adding a link to Why use createEventDispatcher? (Svelte GitHub Issue) comment that covers this nicely, imho:
By using
createEventDispatcher
, you are telling the compiler to compile your component in such a way that any events it emits adheres to the typical CustomEvent interface. This isn't that big of a deal if you are just dealing with Svelte, but I gather that if you are compiling Svelte components to be used elsewhere as web components, your compiled component will be compiled with an interface other frameworks will understand (…).
This makes sense.
Earlier in the thread:
It's now (Mar 2019) a lot easier to have props that are callbacks in Svelte 3, so you'll probably be using events less anyway.
That suggests there might be some evolutionary reason for the two to co-exist.
One more thing: with events, one is tied to the Custom event interface and the .detail
wrapping (that's the whole point!). That may seem like additional complexity to the outer component, whereas with function references one can craft a more slender API.
If one ends up doing function references, notice the <Thing1 {onClick} />
shorthand in the linked issue.
Edit: It doesn't seem that simple. Events are not emitted from components ... (opened Jun 2019) shows that Svelte events aren't fully usable in web components. Until that's resolved, dispatching likely falls in between two worlds. Not really standard. Not really custom.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With