vue
vue copied to clipboard
Provide a way to define different name for prop attribute
What problem does this feature solve?
In most of cases, it's not really comfortable to use initialProp
as prop name, for example, or have normalizedProp
inside a component, which takes some passed prop and transforms it. Code looks bloated and reminds more workaround than a good solution.
Having ability to change attribute name of prop would be great. Something like:
rawProp: { attributeName: "prop" }
What does the proposed API look like?
<component size="md"> ... </component>
computed: {
size: {
switch (this.rawSize) { ... } // returns something in case blocks
}
},
props: {
rawSize: {
attributeName: "size",
type: String
}
}
Thus, using any of proposed solutions above, this.size
inside component would return transformed value (for example, h4
or just 4
).
I believe having this feature would be very awesome and help us to write cleaner code.
I'm interested in this feature too. Is this feature confirmed to be implemented? I'm willing to work on this.
Edit:
I'm currently now working on this, please feel free to jump in.
Besides, there's also another enhancement about props
.
Here's a simple code.
props:{
size: {
type: Number,
}
}
And here's a parent component:
<parent>
<child size="1"></child>
</parent>
We know it's a wrong usage, but I think, now that we provided the field type
, we can call Number(value)
to change it's type?
After seeing this issue, I think maybe my choice can be a default function of his transform
function.
Regarding the transform, it's basically coerce
from Vue 1 and it was removed. The feature request is about having different name locally for a prop but the transform feature has been asked many times already (#2218, https://github.com/vuejs/vue/issues/7657) and it's achievable in userland: https://github.com/posva/vue-coerce-props.
@posva, I've updated FR description.
To give this some life again, I am also very much interested regarding this feature. I would though call it propName
to stay in line with it being props:
props: {
rawSize: {
propName: 'size',
type: Number,
default: 1,
}
}
Here is a Vue mixin (fjc0k/vue-messenger) including a series of useful enhancements to Vue components props:
- Transform props
- Enum-type props
- Numeric-type props
- Listen for receiving props
- Two-way data binding props
Hope this helps.
It's been a while, but I'm going to bring it up again, what's the status of this feature request? Is it confirmed or already implemented?
The proposed (fjc0k/vue-messenger) does not solve the issue. Again, we simply want an alias to prop names, so we wouldn't have to write initialThis
, initialThat
all the time.
I'm willing to work on this feature, is it confirmed/implemented?
I'm also very interested in this. I just have something to point out: Currently we look at props as being a component's documentation. An alias would be just for internal use. Wouldn't it be better if aliases were a separate option? Something like:
export default {
props: {
size: {
type: Number,
default: 100
},
position: {
type: Object,
default: () => ({ x: 0, y: 0 })
}
},
aliases: {
initialPosition: 'position'
}
}
This way, props are kept with just the information the caller needs, nothing more.
Not really because it's part of the prop definition so it belongs in one property. Documentation tools can still skip it
It seems to me that this would be preferable:
props: {
size: {
type: String,
alias: "rawSize"
}
}
Rather than this:
props: {
rawSize: {
type: String,
propName: "size"
}
}
The external facing prop name should remain as the key in the props
object regardless of whether an alias is set or not. Adding an alias for internal use should simply require the addition of a property to that prop spec, not changing the property key.
Here is an example of an existing size
prop which the develop later wants to alias within this component:
Original proposal:
props: {
size: {
type: String
}
}
gets changed to:
props: {
rawSize: {
type: String,
propName: "size"
}
}
My suggestion:
props: {
size: {
type: String
}
}
gets added to:
props: {
size: {
type: String,
alias: "rawSize"
}
}
Edit: Oops, I made a mistake, I was intending to reply to vuejs/rfcs#10. But it's still valid here. I'll reply in there too.
I think the examples list in the Motivation section of the RFC (as well as some use cases commented) are not good arguments for this proposal.
- This example expresses its intent quite accurately, the prop name indicates that it's the initial value, which is different from the internal mutable value. I think making this distinction is preferable.
props: ['initialCounter'],
data() {
return {
counter: this.initialCounter
}
}
- This example is a bit representative for a lot of arguments around the previously commented use cases of props coercion, sanitization or preprocessing in general.
props: ['size'],
computed: {
normalizedSize() {
return this.size.trim().toLowerCase()
}
}
With the introduction of Composition API, those use cases could be handled elegantly:
props: ['size'],
setup(props) {
const size = computed(() => {
return props.size.trim().toLowerCase()
})
return {
size
}
}
That being said, I'm not entirely against this. The Swift example in the RFC regarding argument labels is what in the similar vein with this proposal. Take that example into the context of Vue:
props: {
person: String,
from: {
as: 'hometown',
type: String
}
}
And take the example of the new <teleport>
component (though it's not implemented with normal component options). Its target prop name is to
, but it's not ideal to refer it internally as to
.
For the sole purpose of renaming (or aliasing), we could do it in setup function:
props: {
to: {
type: [String, Element]
}
},
setup(props) {
const target = toRef(props, 'to')
// setting up
return {
target
}
}
But it's not as expressive and cohesive as following IMO:
props: {
to: {
as: 'target',
type: [String, Element]
}
},
setup(props) {
// setting up
return {
//
}
}
So, in summary:
- IMHO it's a bit of a detour to use this feature to solve the problems of props preprocessing of sort.
- This proposal can be useful for providing the feature of argument labels.
This is a cool feature. I think the idea is similar to that of how Swift allows you to have an internal variable and external parameter name. (https://useyourloaf.com/blog/swift-named-parameters/)
Sometimes it makes sense to have verbose external names for clarity, and shorter names inside the component.
For example, a component can have a long name like this:
<MyTable v-bind:userDataFromSomeAPI="data" />
but inside the component I don't want to refer to it as userDataFromSomeAPI
, but just as user
.
So I would really like this! I think as
or alias
are good, though I like as
for brevity.
Another use case for such alias is having components created with :is="component"
where you create completely different components with different internal logic, but you pass data inside of such components with a unified prop, something like payload
, but for clarity reasons you want the prop to be named differently in every component that receives it
Something like from
from provide/inject would be awesome also
https://vuejs.org/v2/api/#provide-inject
inject: {
foo: {
from: 'bar',
default: 'foo'
}
}
It's very annoying to have different names for data
and props
or having ugly hacks like <some-component :props="{myProp: someVal }"/>
to overcome Vue limitations in this area.
Any progress? would be a nice to have...! (my use case is to support international developers, so the prop name is more intuitive in each language)
as a workaround: (in the meantime) add a new prop for every alias, and then using computed value ... but it adds more lines to the component (compared to a simple one line as @hrobertson suggested with:
props: { size: { type: String, alias: "rawSize" } }
Another use case for such alias is having components created with :is="component" where you create completely different components with different internal logic, but you pass data inside of such components with a unified prop, something like payload, but for clarity reasons you want the prop to be named differently in every component that receives it
This is my use case. Currently what I do isn't terrible, just looking for more elegance and eliminating one extra variable:
<component :is="component" :payload="data" />
With 20 components or so, and inside any given component pass prop payload into a const.
Example: Customer component:
const props = defineProps<{
payload: any
}>()
const Customer = computed(() => props.payload)
Which allows me to use Customer
in the template, and not payload
peppered everywhere.