Replies: 26 comments 44 replies
-
I believe, stopping to support old syntax by default could be the best. |
Beta Was this translation helpful? Give feedback.
-
I feel that abandoning Emit is still very good, Emit is a bit too complicated |
Beta Was this translation helpful? Give feedback.
-
Sorry, i'm noob. |
Beta Was this translation helpful? Give feedback.
-
How do I replace construction like @click="!disabled && $emit('click')"? |
Beta Was this translation helpful? Give feedback.
-
I find myself comfortable with the logic of <script lang="ts" setup>
type Item = {
key: string,
title: string,
onClick?: () => void
}
defineProps<{
items: Item[],
current?: string,
}>();
defineEmits<{
(e: 'update:current', payload: string),
}>();
function handleClick(item: Item) {
emit('update:current', item.key)
item.onClick.?();
}
</script>
<template>
<nav>
<ol>
<li v-for="item in items" :key="item.key">
<button @click="handleClick(item)">{{ item.title }}</button>
</li>
</ol>
</nav>
</template> |
Beta Was this translation helpful? Give feedback.
-
It depends. As a huge open-source framework, there are a lot of people who prefer these syntax sugars. It's an optional usage. |
Beta Was this translation helpful? Give feedback.
-
I don't really see how this is simpler I have a hard time understanding what you are actually doing. Is the idea that people pass a function into the component from the parent? I don't understand your example. Besides, I think deprecating emit and v-model is not a good idea. Think about all the code that is written like this. Way too much. |
Beta Was this translation helpful? Give feedback.
-
Why not just use React and let Vue be like it is. I mean don't get me wrong but those sugar are essential things of Vue. two way binding, component emits. props vs emits: I think the sugar helps to simplify the understanding of wat a component do. Props are input events are output. Props vs v-model: we like that magic and now with defineModel is sweeter and more simple. The post of the creator of naive is right about ts issues with the current tooling but is more about someone missing react syntax. |
Beta Was this translation helpful? Give feedback.
-
@yyx990803 What's you take on this? |
Beta Was this translation helpful? Give feedback.
-
I'm confused; what about v-model modifiers like Or isn't this the |
Beta Was this translation helpful? Give feedback.
-
I played around a little using props instead of emits, and didn't hit any roadblocks so far. The only problem right now is devtools support - you don't have Component events anymore. |
Beta Was this translation helpful? Give feedback.
-
I assume the point of events is to discourage any component from changing its parent's data (except explicitly with models). That's great conceptually. I think it could just be more concise and consistent: <script setup>
// reactive variant of https://vue-macros.sxzz.moe/macros/define-prop.html#johnson-s-edition
// inspired by https://vue-macros.sxzz.moe/features/export-props.html
let count = $prop(0)
let user = $prop<User>()
// reactive variant of defineModel({ local: true }) with default value
let modelValue = $model(0)
// reactive variant of defineModel("userModel")
let userModel = $model<User>()
// identical to https://vue-macros.sxzz.moe/macros/define-emit.html
let increment = $event()
let add = $event<[amount: number]>("incrementBy")
</script> @sxzz How do you decide which macros to make? I actually came here looking for the origin of |
Beta Was this translation helpful? Give feedback.
-
The current workaround is to add the following ESLint rules to ban {
"no-restricted-syntax": [
"error",
{
"message": "emit is not allowed, use props instead.",
"selector": "[name=emit]"
},
{
"message": "$emit is not allowed, use props instead.",
"selector": "[name=$emit]"
}
],
"vue/no-restricted-syntax": [
"error",
{
"message": "emit is not allowed, use props instead.",
"selector": "[name=emit]"
},
{
"message": "$emit is not allowed, use props instead.",
"selector": "[name=$emit]"
}
]
} |
Beta Was this translation helpful? Give feedback.
-
I think But <script setup>
const props = defineProps({
onOk: Function
})
const emit = defineEmits(['cancel'])
function handleOk () {
const fromParentValue = props.onOk('To parent')
alert(`Parent return value is "${fromParentValue}", USE PROP event support two-way value.`)
}
function handleCancel () {
emit('cancel', 'To parent')
alert('USE EMIT, only support child emit value to parent callback.')
}
</script>
<template>
<button @click="handleOk">Ok</button>
<button @click="handleCancel">Cancel</button>
</template>
|
Beta Was this translation helpful? Give feedback.
-
You are right, the Vue team is not yet perfect, because there are still many important things to do, such as language-tools issue has 156 issues. It's not that v-model is bad, but that it prompts an exception in tsx. If you want the best service, you should choose what they recommend. It's like going to KFC and not getting the best coffee. Good luck. |
Beta Was this translation helpful? Give feedback.
-
When I started with Vue few years ago it's actually the confusion caused by emit that made me switch to React for years, now I don't have problems with emit (although I prefer to avoid it) and find
|
Beta Was this translation helpful? Give feedback.
-
Emits' main architectural advantage is that they are fire-and-forget (like DOM events). One component should never need to know if its parent component handles the event or not; just like a component should not rely on whether its parent uses Converting all emits to props is also prone to boilerplate, either:
Also, emiting dynamic events (a rare need, indeed) is less convenient: this.$emit(`update:${key}`, value) versus this.$props[`onUpdate${capitalize(key)}`]?.(value) |
Beta Was this translation helpful? Give feedback.
-
我注意到在一些UI库中是不适用emits的。他们在props中定义emit事件,这些都是vue3比较流行的库, 例如:
我们确实应该考虑下emits的必要性了。 |
Beta Was this translation helpful? Give feedback.
-
Yes, in our code-base we're not using emits because they're not type-safe. Still have to deal with it in Vuetify tho, I think having events that may or may not be handled makes more sense for 3rd party libs. But I guess you can just have an optional prop for that. Also The only concern I have is that all those defineProps/defineEmits/defineModel doesn't seem to work with |
Beta Was this translation helpful? Give feedback.
-
Svelte and Qwik both offer Two-way Binding, which helps users to simplify their usage. <script setup>
import { ref } from 'vue';
const value = ref('');
</script>
<template>
<input v-model="value">
<p>{{ value }}</p>
</template> <script>
let value = '';
</script>
<input bind:value>
<p>{value}</p> import { component$, useSignal } from '@builder.io/qwik';
export const App = component$(() => {
const value = useSignal('');
return (
<>
<input bind:value={value} />
<p>{value}</p>
</>
);
}); |
Beta Was this translation helpful? Give feedback.
-
Totally agree 💯 Here is an example of how hard is it to handle <script setup lang="ts">
import type { CheckboxRootEmits, CheckboxRootProps } from 'radix-vue'
import { CheckboxIndicator, CheckboxRoot, useEmitAsProps } from 'radix-vue'
import { Check } from 'lucide-vue-next'
import { cn } from '@/lib/utils'
const props = defineProps<CheckboxRootProps>()
const emits = defineEmits<CheckboxRootEmits>()
const { class: className, ...restOfAttributes } = useAttrs()
const emitsAsProps = useEmitAsProps(emits)
</script>
<template>
<CheckboxRoot
v-bind="{ ...props, ...emitsAsProps, ...restOfAttributes }"
:class="
cn('peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground', className ?? '')"
>
<CheckboxIndicator class="flex items-center justify-center text-current">
<Check class="h-4 w-4" />
</CheckboxIndicator>
</CheckboxRoot>
</template> |
Beta Was this translation helpful? Give feedback.
-
I'm a fan of simply removing |
Beta Was this translation helpful? Give feedback.
-
Guys I think this part of the video demonstrates the problems with emits very well. |
Beta Was this translation helpful? Give feedback.
-
Is it possible if props.onXXX adapted to @update:xxx automatically? this deepens the magic |
Beta Was this translation helpful? Give feedback.
-
Vue is not yet ripe for tsx and full typing( Try this - https://vue-macros.dev/interactive/. I didn't use it because half of my team uses webstorm |
Beta Was this translation helpful? Give feedback.
-
After using Svelte 5 event/props model it, for me it was far more easer to work with compared to Vue. The big reason is consistency. You get what you define nothing more nothing less. In Vue case you have no way to know which events are required, which ones are optional, fallthrough attributes make it harder still. If you try to be more strict with Vue events do not bubble (except native ones) so in my opinion making them just functions would allow to reuse infra we already have for props: typesafety, spreading, simpler model without any major downsides. Of course ecosystem is very large at this point and moving everything would be hard, but with enough push and codemods it would be worth it. |
Beta Was this translation helpful? Give feedback.
-
Currently, to define props and events, we've got
props
,emits
,defineProps
,defineEmits
, and a possibledefineModel
, each of them has different syntaxes, doubled or even tripled when using TypeScript. Even as a Vue veteran, that's a lot to digest and remember, which deviates from Vue's design philosophy of being simple and beginner-friendly, as a long-time Vue user, I don't see Vue going in the right direction.Functionally, props can do all
emit
+v-model
can do but in a more explicit, less magical, and more type-friendly way. There were countless times that we rewrotev-model
to:prop
+@event
becauseemit
andv-model
could not meet the needs, e.g.To replace
emit
with props, in the child component, we use@event="onVisibleChange($event)"
(notice, not@event="props.onVisibleChange($event)"
, since props can be used directly in the<template>
) instead of@event="$emit('visibleChange', $event)"
.In the parent component,
<child @visible-change="visible = $event" />
still works, since under the hood, it's compiled toonVisibleChange: ($event) => $setup.visible = $event
.Too many options to achieve the same functional goal create code inconsistencies and unnecessary debates, increase the framework learning curve, and are a huge maintenance burden both for the framework maintainers and users e.g. tooling support, more unnecessary new concepts to learn, more ESLint rules need to be created and applied, etc.
emit
andv-model
served us well in Vue 2 with JavaScript, and we didn't need to write types for them, but when combining Vue 3 with TypeScript,emit
andv-model
have generated too many unnecessary complexities.Popular Vue 3 UI libraries don't use
emit
in their component definitions.v-model
causing type-checking blind spots.I realized this post is too ahead of time for some people, it's futile to convince them, therefore, I won't reply any longer.
Beta Was this translation helpful? Give feedback.
All reactions