1

Reading the code on this amazing Modal example: https://svelte.dev/examples#modal I'm trying to understand what's the difference in terms of performances/bundle size/other if I use:

  1. createEventDispatcher() with directive like on:close={()=> doSomething()} or
  2. simply pass the function as a value like action={doSomething}.

Also in the first case I can't use on:close={...} on the slots, right?

If I try it gives me this error: [!] (plugin svelte) ValidationError: <slot> cannot have directives

What do you recommend to use?

Fred Hors
  • 3,258
  • 3
  • 25
  • 71
  • Does this answer your question? [Svelte: Event forwarding with dispatcher vs passing in handling function, which is best practice?](https://stackoverflow.com/questions/61569655/svelte-event-forwarding-with-dispatcher-vs-passing-in-handling-function-which) – Stephane Vanraes Jun 09 '20 at 14:02

1 Answers1

4

Passing a callback is the most straightforward. Light. Simple. In most cases, a callback can do, and IMO they're preferable.

You can pass only one callback, though, whereas you can have multiple listeners on the same event.

<script>
    import { onMount } from 'svelte'
    import Beeper from './Beeper.svelte'

    let beeper

    onMount(() => {
        const disposes = [
            beeper.$on('beep', () => console.log('dynamic A')),
            beeper.$on('beep', () => console.log('dynamic B'))
        ]
        return () => disposes.forEach(fn => fn())
    })
</script>

<Beeper on:beep={() => console.log('inline')} bind:this={beeper} />

Perhaps more interesting with standalone components?

const beeper = new Beeper({ target: document.body })
beeper.$on('beep', ...)
beeper.$on('beep', ...)

Events can also be easier to proxy:

Proxy.svelte

<script>
  import Beeper from './Beeper.svelte'
</script>

<Beeper on:beep />

App.svelte

<script>
  import Proxy from './Proxy.svelte'
</script>

<Proxy on:beep={() => console.log('beep')} />

On the other hand, events can be a bother to proxy:

Proxy.svelte

<script>
  import Beeper from './Beeper.svelte'
</script>

<!-- callbacks are all in the $$props bag, but I have to know every
     event that I want to proxy -->
<Beeper {...$$props} on:beep />

And they're even only arguably easier to proxy:

<script>
  import Beeper from './Beeper.svelte'

  export let onBeep
</script>

<Beeper {onBeep} />

Also, I'm not sure you can have callbacks with the custom element flavor of Svelte, so you're possibly stuck with events there.

There are also situations where you might prefer the event API for consistence (especially when your component closely mimic an existing DOM element), elegance or aesthetic reasons.

Personally, I generally just go with callbacks unless a callbacks won't do. That's pretty infrequent.

Ah! And no, you can't have events on a slot. But you can't really have a callback either, can you?

<slot onBeep={onBeep} />

This would make the onBeep function available as let:onBeep in a consumer component:

<SlotBeeper let:onBeep>
  {@debug onBeep}
  <AnotherCmp {onBeep} />
</SlotBeeper>
rixo
  • 23,815
  • 4
  • 63
  • 68