vuejs/rfcs

v-bind support binding multiple objects

sqal opened this issue · 7 comments

sqal commented

What problem does this feature solve?

Currently, if we want to pass attributes from multiple sources we have to manually import mergeProps helper and do

<MyComponent v-bind="mergeProps($attrs, featAProps, featBProps)" />

or use computed property

It would be better if we could just do:

<script setup>
  const featAProps = useFeatureA()
  const featBProps = useFeatureB()
</script>

<template>
  <MyComponent v-bind="[$attrs, featAProps, featBProps]" />
</template>

What does the proposed API look like?

Allow passing an array of props to v-bind v-bind="[x,y,..]"

Currently most scripts use {...$attrs, ...featAProps, ...featBProps}
Is it really neccessary to introduce the array form?

I agree, I don't think we need to add another variation to this API.

@posva I think this is not a issue...
we have native ES syntax for combining multiple objects
{...$attrs, ...featAProps, ...featBProps}
I think this issue can be closed.

sqal commented

@cyfung1031 using spread operator or Object.assing would result in overriding props instread of merging them. What if featAProps have onClick/class and featBProps as well? that's why you have to use mergeProps

@cyfung1031 using spread operator or Object.assing would result in overriding props instread of merging them. What if featAProps have onClick/class and featBProps as well? that's why you have to use mergeProps

This is another issue. You are not asking for binding multiple objects. You are asking for binding multiple methods to the same attribute in the same component.

You should open another issue for this. They are different.

The working principle for v-bind is based on the key-value relationship.

This seems to be supported (accidentally?) only if you have other attributes bound too.

// Works
<MyComponent foo="bar" v-bind="$attrs, featAProps, featBProps" />
// Doesn't
<MyComponent v-bind="$attrs, featAProps, featBProps" />

This is because attributes + v-bind is compiled directly to a mergeProps call:

_createBlock(_component_MyComponent, _mergeProps({ foo: "bar" }, _ctx.$attrs, _ctx.featAProps, _ctx.featBProps), null, 16 /* FULL_PROPS */)

But v-bind alone uses guardReactiveProps instead which only accepts a single argument:

_createBlock(_component_MyComponent, _normalizeProps(_guardReactiveProps(_ctx.$attrs, _ctx.featAProps, _ctx.featBProps)), null, 16 /* FULL_PROPS */)

Related: vuejs/eslint-plugin-vue#1731

This seems to be supported (accidentally?) only if you have other attributes bound too.

// Works
<MyComponent foo="bar" v-bind="$attrs, featAProps, featBProps" />
// Doesn't
<MyComponent v-bind="$attrs, featAProps, featBProps" />

This is because attributes + v-bind is compiled directly to a mergeProps call:

_createBlock(_component_MyComponent, _mergeProps({ foo: "bar" }, _ctx.$attrs, _ctx.featAProps, _ctx.featBProps), null, 16 /* FULL_PROPS */)

But v-bind alone uses guardReactiveProps instead which only accepts a single argument:

_createBlock(_component_MyComponent, _normalizeProps(_guardReactiveProps(_ctx.$attrs, _ctx.featAProps, _ctx.featBProps)), null, 16 /* FULL_PROPS */)

Related: vuejs/eslint-plugin-vue#1731

Is this still considered a bug or is it a feature? It seems to still work in Vue 3 without any errors and I only have a separate class attribute on it, not even a prop