sveltejs / svelte

Cybernetically enhanced web apps
https://svelte.dev
MIT License
78.67k stars 4.13k forks source link

Auto-dispatch #9060

Closed ethanlal04 closed 1 year ago

ethanlal04 commented 1 year ago

Describe the problem

I really love Svelte and think its awesome. But like anything else in life, its not perfect.

One of the things I totally hate is the amount of boilerplate you need to dispatch a simple event.

Just look at this:

<script>
  import { createEventDispatcher } from 'svelte';

  const dispatch = createEventDispatcher();

  function dispatchSay(text) {
    dispatch('say', text);
  }
</script>

<button on:click={() => dispatchSay('Hi')}>
  Say 'Hi'
</button>

Hellfire, right?

React has a much simpler way to do this, i.e. no way. People just carry in event handlers like props and call them as needed inside the child component. Its simple and needs zero lines of code. But, having actual DOM-like events can be powerful as it lets you access the event object, which you can't in handler prop functions. Also, it makes it similar to handling regular events raised by DOM elements which we are all familiar with.

Describe the proposed solution

To get the best out of both worlds, I came up with this syntax:

<script>
  export function say() {}
</script>

<button on:click={() => say('Hi')}>
  Say 'Hi'
</button>

How cool is that? Here, the function say() is the dispatcher. Calling it dispatches the event say, named after itself.

I think this syntax is perfect cuz

  1. It's just 1 line of code.
  2. It's totally valid JS.
  3. The syntax (outside of context="module") currently doesn't seem to do anything than declare a function say(). Idk, I played with it a bit.
  4. It's similar to the style Svelte deals with props and thus consistent.

From the perspective of the parent component, this should look the same as a manually dispatched event.

<script>
  import Inner from './Inner.svelte';

  function handleSay(event) {
    alert(event.detail.text);
  }
</script>

<Button on:say={handleSay} />

The body part of export function say() {} though, having no role in the dispatch, yet being there, kinda bugged me. After some thought, I realized that it can hold the default behaviour of the event just like that in a regular DOM event. Funnily, it's similar to setting the default value of a prop. Anyway, I think this can turn out quite powerful. To do so, we can optionally take in the detail parameter (renamed to whatever) inside the dispatcher and do something useful with it like this:

export function say(text) {
  // Do something useful by default
}

Don't want this functionality? Just leave the body empty and no need to accept the 'text' parameter!

As for createEventDispatcher(), I'm not saying we should get rid of or deprecate it. It can sit around, doing no harm, to not break any existing code. Maybe, auto-dispatch (as I call this thing) can be syntactic sugar over manually creating dispatchers, just like auto-subscription is for manually handling store subscriptions.

I think this would be a fine addition to Svelte. Thoughts?

Alternatives considered

None.

Importance

would make my life easier

gtm-nayan commented 1 year ago

Duplicate of #5602

Conduitry commented 1 year ago

Exporting a function in the <script> block does do something currently - it creates a method on the component instance. We shouldn't hijack that and switch it (in some cases) to be related to event emitting. I'd probably be in favor of closing #5602 as well.

There's also already #3488 for reducing the boilerplate with emitting events in other ways.