vuejs / core

🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
https://vuejs.org/
MIT License
47.69k stars 8.33k forks source link

Call emits with return result #8865

Open uktamka opened 1 year ago

uktamka commented 1 year ago

What problem does this feature solve?

It would be nice if emits('custom-emit') returned a result, so we don't need to create an extra key in props.

What does the proposed API look like?

ParentComponent.vue

<script setup lang="ts">
import ChildComponent from '@/components/ChildComponent.vue'
const onClickChildComponent = (value: string) => value + ' world!'
</script>
<template>
  <div>
   <ChildComponent @custom-emit="onClickChildComponent" />`
  </div>
</template>

ChildComponent.vue

<script setup lang="ts">
const emits = defineEmits<{
  (e: 'custom-emit', value: string): string
}>()

console.log(emits('custom-emit', 'Hello')) // ==> 'Hello world'
</script>
<template>
  <div></div>
</template>
LinusBorg commented 1 year ago

Id argue that you are then no longer emitting an event, really. Emitting an event means the child is not concerned with what happens with the emitted value.

If your component does depends on the return value, defining that as a prop is fine and the way to go.

uktamka commented 1 year ago

Id argue that you are then no longer wmittinf an event, really. Emittinf an event means the child is not concerned with what happens with the emitted value.

If your component does depwnd on the return value, defining that as a prop is fine and the way to go.

What if I have a lot of paragraphs in the child component, when selecting using Selection one of the paragraphs is sent to the parent component that has business logic.

How can I find out which paraph has changed using props?

If I put this business logic in a child component, then I have to create many similar components as a child or pre-create all types of logic in the child component.

And why do we have in defineEmits return type if emits always return void?

jacekkarczmarczyk commented 1 year ago

If you need a result from the handler then use defineProps instead of defineEmits

And why do we have in defineEmits return type if emits always return void?

You don't need to, you can use the syntax that doesn't require providing a return type (see Vue docs for details)

uktamka commented 1 year ago

If you need a result from the handler then use defineProps instead of defineEmits

And why do we have in defineEmits return type if emits always return void?

You don't need to, you can use the syntax that doesn't require providing a return type (see Vue docs for details)

Yes, but we can specify the return type. And if we can, then we can expect this type.

nopeless commented 1 year ago

I agree with this issue

At the very least, defineEmits have to be updated, because it seems to reflect the return value of the event executor.

Here is a repro

https://stackblitz.com/edit/nuxt-starter-h7hy96?file=components%2FEmitMe.vue,app.vue,tsconfig.json

However, I think it would be better if the developer is allowed to return from an event handler. SortableJs does this

MQYForverT commented 1 year ago

我认为你真的不再发布事件了。发布事件意味着子进程不关心发布的值会发生什么。

如果你的组件确实依赖于返回值,那么将其定义为 prop 就可以了。

比如我渲染一个树形结构数据,使用递归去渲染组件A,在组件A里面有一个删除按钮,我在点击这个删除时,默认是直接删除。

但是我现在想让父组件决定到底删不删,于是我emit一个事件出去,父组件定义回调,并在回调用弹出一个弹框,请问是否确认删除,确认返回true,否返回false。

在子组件中优先判断父组件是否注册了这个回调,如果没有,则执行默认逻辑。如果有,则根据父组件的返回值执行相关逻辑,接收到true,执行默认逻辑,接收到false,执行不删除。

nopeless commented 1 year ago

@jacekkarczmarczyk What do you think about my comment?

zhengyimeng commented 1 year ago

为何一定要维护 emit? 而不是通过 props 接收事件?props 能做 emit 所能做的所有事情

Justineo commented 1 year ago

IMO, the focus of emitting event is more on decoupling. It is used to notify the outside world of internal state changes, but it does not care much about the external responses. DOM events do have a restricted mechanism for controlling subsequent behavior (e.g. stopPropagation, preventDefault, etc.), but we don't have such a unified event model in Vue. If a component wants to control internal behavior or state flow through external logic, it's recommended to use a function prop to yield a portion of the logic to external control.

nopeless commented 1 year ago

@Justineo What do you think about my comment?

shenjunjian commented 2 months ago

In the inner of the vue runtime, props and emits are same functions, For example, : emits('custom-emit','Hello'), You can write as : const retValue = props.onCustomEmit('Hello')

//在vue的runtime中, props, emits是互通的功能,