Subscribe on changes!

Option to not automatically pass props to template (explicitProps: true)

avatar
May 31st 2021

What problem does this feature solve?

Often prop values need to be modified or normalized before they are used internally. For example, a prop may accept a number, string or Date and then normalize all those values by converting them all to a Date. This normalization is usually done using a computed. You might assume that since props are passed to the Setup, you would have to explicitly return them in order for them to be available in the template. However, naming the computed the same as the prop and returning it from Setup gives a "duplicate key" error. This is compounded if you want to use props: true in Vue Router.

When using the composition API, there's more of an expectation of explicit behaviour. It would be useful if there was a component option to disable the automatic passing of props to the template.

What does the proposed API look like?

On the component, have an explicitProps: true option.

An example that passes some props and excludes others from the template.

export default defineComponent({
  explicitProps: true,
  props: ['id', 'another'],

  setup(props) {
    // only 'id', and not 'another', is passed to template
    return {
      id: props.id
    }
  }
}

Here is an example of using a computed in place of a prop

export default defineComponent({
  explicitProps: true,
  props: ['id', 'another'],

  setup(props) {
    let id = computed(() => props.id.toUpperCase())

    // return computed id in place of prop
    return {
      id
    }
  }
}

There's lots of additional destructuring tricks that can be done with toRefs() to mix and match computed values with

export default defineComponent({
  explicitProps: true,
  props: ['id', 'another'],

  setup(props) {
    const { id: propId, ...rest } = toRefs(props)

    let id = computed(() => propId.value.toUpperCase())

    return {
      id,             // computed value
      ...toRefs(rest) // rest of props, not certain if this wrap is needed?
    }
  }
}

Finally, replicating the current Vue behaviour using toRefs() on the props

export default defineComponent({
  explicitProps: true,
  props: ['id', 'another'],

  setup(props) {
    return {
      ...toRefs(props)
    }
  }
}
avatar
May 31st 2021

So you want an option to disable the ability to use this.aProp and aProp just so it's possible to reuse the same name to create a normalized/transformed version of a prop.

This looks rather confusing when reading a component props and then checking its template and other methods (for people not using setup).

If a value needs normalization, what wrong with naming it accordingly?

For the router, note you can use the function version of props to normalize them

avatar
May 31st 2021

It isn't just to be able to reuse the name. It would also be useful for migration to the composition API by being explicit about which values are returned to the template. As a long-time Vue 2 user, the props being appended to this made sense to me. However, the composition API is so explicit with a props argument and a return object, it feels strange that values can get past it automatically.

My idea is to include an option for those of us who have fully bought in to the composition API in Vue 3 to have better control of our props.

avatar
May 31st 2021

It would also be useful for migration to the composition API by being explicit about which values are returned to the template

I don't understand why this is different from being able to reuse the prop name. props are always available, so I don't see why this would help in migration either.

I think you should follow the RFC process in the rfcs repository

avatar
May 31st 2021

Agree with posva. See:

https://github.com/vuejs/rfcs