feat(runtime-core): return result of handlers in `emit`
It would be great if emit could return the result of the handlers. A typical example could be to show a loading indicator while asynchronous event handlers are running:
const loading = ref(false)
const handleClick = async () => {
loading.value = true
await Promise.all(emit('click'))
loading.value = false
}
This is just a basic example that does not consider errors or multiple clicks but it gives an idea what would be possible. The same could already be implemented with props but it duplicates the handling.
If you think this is a good idea, I can extend the PR with corresponding tests.
I'm not sure if we should have an issue discussing this feature first.
Yep, for sure, I thought this PR could serve as an initial base to discuss it further. Happy to move it somewhere else if you want?
Deploy Preview for vuejs-coverage failed.
| Name | Link |
|---|---|
| Latest commit | a1cac63b1cc39f87733b0eea45ee259412af8373 |
| Latest deploy log | https://app.netlify.com/sites/vuejs-coverage/deploys/633d2b62989f1b000874005a |
It's an underrated feature here! First of all, it would really be nice to have:
<!-- Outside -->
<SomeFormComponent
@validate="validateData"
@submit="saveDataToDatabase"
/>
<script>
async function validateData() {
await API.validateXXX()
}
async function saveDataToDatabase() {
await API.postXXX()
}
</script>
<!-- Inside -->
<form />
<script>
const emit = defineEmits()
async function handleClickSubmit() {
startLoading()
await emit('validate', data)
await emit('submit', data)
stopLoading()
}
</script>
Nice and clean, right? But for now, we can't write in this way. Because there is actually an untold rule on event handlers.
defineEmits<{
(e: 'submit'): Promise<undefined> // ❌
(e: 'submit'): void // ✅
}>()
The return type can only be void.
You won't get the result returned by your event handlers.
The whole EMIT thing is basically an EventEmitter, and in a typical EventEmitter model, one event key can have multiple handlers.
Despite the fact that @sxzz has looked up the code, and handler won't be an array.
So, Vue should make a decision on its Emit model.
Either Vue supports Returning result of event handlers or stress the void type in doc like:
defineEmits<{
(e: 'aaa'): void
(e: 'bbb'): void
/** .... */
}>()
I realy need this feature, is this feature likely to be merged? when will it be available?
There's an RFC discussion at https://github.com/vuejs/rfcs/discussions/587 that proposes a slightly different way of approaching this. I'm not sure which I prefer.
Just to clarify, a single event can have multiple listeners. In the Playground below, the emitted event triggers 3 handlers. mergeProps ensures that these are combined into an array.
emit will need to return an array in all cases, it can't just assume a single listener. The RFC above seems to be suggesting that the array should be automatically wrapped in a promise, whereas the approach here seem to leave it to the user to call Promise.all.