Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve the props parameter in setup function #3288

Closed
Justineo opened this issue Feb 23, 2021 · 6 comments
Closed

Improve the props parameter in setup function #3288

Justineo opened this issue Feb 23, 2021 · 6 comments
Labels
✨ feature request New feature or request

Comments

@Justineo
Copy link
Member

What problem does this feature solve?

import { defineComponent, toRefs, watch } from "vue";

export default defineComponent({
  props: {
    foo: Boolean
  },
  setup(props) {
    const { foo } = toRefs(props);

    // As `foo` might be undefined instead of a Ref
    // we cannot watch it directly like this
    watch(foo, () => { ... }); 
  }
});

Instead, we need to use:

watch(() => props.foo, () => { ... });

So we need to switch to props.foo whenever we need to watch it, which doesn't feel very natural to me.

What does the proposed API look like?

For all declared props, always provide { [propName]: undefined } in the props parameter of the setup function so that we can write:

setup(props) { // props being { foo: undefined }
  const { foo } = toRefs(props);

  // foo is Ref
  watch(foo, () => { ... }); 
}
@Justineo Justineo added the ✨ feature request New feature or request label Feb 23, 2021
@posva
Copy link
Member

posva commented Feb 23, 2021

How would you differentiate a prop passed as undefined from a missing prop?

Wouldn't make more sense to do:

const foo = toRef(props, 'foo')

Edit: Although this is technically a breaking change, having the key with undefined seems to be more flexible, especially with toRefs() (which otherwise breaks). The limitation would be not being able to detect if a prop is missing when undefined is an allowed value (not Booleans basically). e.g. if the user is passing undefined, which I don't think one should do because they should be passing null instead, to tell the component the prop is empty

@HcySunYang
Copy link
Member

If a prop is missed, it will not appear in props:

{
  props: {
    foo: {
      type: String
    }
  },
  setup(props) {
    console.log(Object.keys(props)) // []
    const { foo } = toRefs(props) // foo is `undefined`
  }
}

So I think it is as expected

@Justineo
Copy link
Member Author

Justineo commented Feb 23, 2021

How would you differentiate a prop passed as undefined from a missing prop?

@posva Hmmm this is a valid point. Maybe we do need to use toRef on individual prop instead as you suggested.

@HcySunYang I think @posva is right if we always provide undefined for missing prop there will be no way to tell if it comes from users.


So maybe we should only use toRefs to convert required props (or with default values) to refs. I'm closing this one 😄

@pikax
Copy link
Member

pikax commented Mar 30, 2021

How would you differentiate a prop passed as undefined from a missing prop?

What would be the use case for an optional prop that wasn't passed in to the component?

<my-comp/>
<my-comp :foo="undefined"/>

<script>
props : {
 foo: String
}
</script>

That code should behave the same.


This behaviour gets really inconsistent when you use a Boolean instead of a String example


This behaviour is different from v2 options API with options API the properties will always be defined.
If this is intended it needs to be marked as breaking change from v2

// vue2
{
  props: {
    foo: String
  },

  data(){
    return {
      hasKey: 'foo' in this.$props // true
    }
  }
}

// vue3
{
  props: {
    foo: String
  },

  data(){
    return {
      hasKey: 'foo' in this.$props // false
    }
  }
}

Altho I still dont know the use case for handling an optional property without default (aka undefined) differently from undefined

@Justineo
Copy link
Member Author

After some discussion with @pikax I think this issue should be reopened. As with current implementation, we actually cannot reliably detect missing props with a simple key in props check, while improving the experience of toRefs may bring more benefits.

@Justineo Justineo reopened this Mar 30, 2021
@logaretm
Copy link

logaretm commented May 8, 2021

This did break prop pass detection that I was relying on as reported in logaretm/vee-validate#3294

As a workaround I had introduced a symbol as a default value to detect when the user didn't pass the prop:

export const EMPTY_VALUE = Symbol('Default empty value');
``

```js
{
  modelValue: {
    type: null,
    default: EMPTY_VALUE,
  },
}

This should probably be marked as a breaking change in the changelog.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
✨ feature request New feature or request
Projects
None yet
Development

No branches or pull requests

5 participants