<script setup> : Make it possible to call defineProps many times
Slokilla opened this issue · 10 comments
What problem does this feature solve?
As a Vue user, what i love the most from Vue 3 and composition API is the way we can arrange the code by logical unit. The component becomes pleasant to read.
To improve this feeling, it would be great to define some feature related props, in each logical unit. So we don't have to scroll to the document top to check props parameters.
What does the proposed API look like?
I actually don't know Vue API enough to implement a feature, so if this feature is judged interesting, I will first have to learn how Vue is internally designed.
Maybe we will have to expose another method, registerProps()
.
We can imagine that registerProps
will aggregate all the props definitions, before calling the usual defineProps
.
I think the final api should look like :
registerProps(['a', 'b'])
/* Code that uses a and b */
registerProps(['c'])
/* Code that uses c */
Seems to be duplicate of vuejs/core#6400
See also vuejs/core#6400 (comment)
You think so ? My proposition looks far less ambitious. I mean, the function could only be called at root level, as defineProps.
I think that you should see it as a syntaxic sugar for defineProps(['a', 'b', 'c'])
, but distributed among logical units in your code.
Could you please provide a more detailed SFC example (<script setup>
) of the proposal?
I think it would look like this :
<template>
<p>Hello {{ username }}</p>
<p>{{ counter }} is {{ parity }}</p>
</template>
<script setup>
import { computed, registerProps, created } from 'vue'
// User name logic
const userProps = registerProps({ userId : {type: Number, required: true } })
const username = ref('')
onBeforeMount(() => {
username.value = fetchUsernameById(userProps.userId)
})
// Counter logic
const counterProps = registerProps({ counter: { type: Number, required: true } })
const parity = computed(() => { return counterProps.counter % 2 === 0 ? 'even' : 'odd' })
</script>
and it should be equivalent to something close to :
<template>
<p>Hello {{ username }}</p>
<p>{{ counter }} is {{ parity }}</p>
</template>
<script setup>
import { computed, defineProps, created } from 'vue'
const props = defineProps(
{ userId : {type: Number, required: true } },
{ counter: { type: Number, required: true } }
)
// User name logic
const userProps = { userId: props.userId }
const username = ref('')
onBeforeMount(() => {
username.value = fetchUsernameById(userProps.userId)
})
// Counter logic
const counterProps = { counter: props.counter }
const parity = computed(() => { return counterProps.counter % 2 === 0 ? 'even' : 'odd' })
</script>
🤔 To be honest, I don't like this proposal personally. IMHO it's unnecessary. Maybe that's not the way that Vue recommended? I'm not sure. More opinions are welcome.
You should manage in a unified place, not scattered anywhere, and the statements in<script setup>
are static, so your approach seems meaningless
I don't think this is a good idea either because it brings little benefit while probably adding a performance impact on tools.
Differently from other composables, props usually form one business logic unit and make sense together as the component arguments
This would help in ways to create utility methods like twoWayProp("x") would create an "x" prop and define "update:x" emit
This is my opinion but I like this idea, but I guess would be better to define single props & emits, like the example below.
// Props
const count = defineProp(1) // default value 1
const count = defineProp<number>() // prop type number
// Emits
const updateCount = defineEmit('update:count')
const updateCount = defineEmit<number>('update:count') // emit type arg number
const updateCount= defineEmit('update:count', (value: number) => value < 3)) // validation
In this way we could organize the code even better by “Logical Concern”
// Count
const count = defineProp(1)
const updateCount = defineEmit('update:count')
// Multiply count
const multipleBy = defineProp(2)
const result = computed(() => count.value * multipleBy.value)