vuejs / rfcs

RFCs for substantial changes / feature additions to Vue core
4.85k stars 551 forks source link

v-bind support binding multiple objects #550

Closed sqal closed 11 months ago

sqal commented 3 years ago

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,..]"

cyfung1031 commented 2 years ago

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

LinusBorg commented 2 years ago

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

cyfung1031 commented 2 years ago

@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 2 years ago

@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 commented 2 years ago

@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.

KaelWD commented 2 years ago

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: https://github.com/vuejs/eslint-plugin-vue/issues/1731

ThaDaVos commented 1 year ago

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