Subscribe on changes!

do not require Props when using defineComponent with setup function

avatar
Apr 16th 2022

What problem does this feature solve?

I like that you can pass a setup function into defineComponent however if you require props in your component you then need to pass a component options object.

What does the proposed API look like?

I want to simply do this:

const MyComp = Vue.defineComponent((p: { name: string }) => {
    return <div>{p.name}</div>;
});

instead of

const MyComp = Vue.defineComponent({
    props: {
        name: String
    },
    setup(p) {
        return <div>{p.name}</div>;
    }
});

This makes it look much cleaner and decreases a level of indentation.

This is even cleaner and works without explicitly setting props:

const MyComp = (p: { name: string }) => {
    return <div>{p.name}</div>;
};

however it only works as a "Functional Component" and does not keep state. React lets me define components like this. In React I use Mobx to get Vue like Reactivity so I need to wrap my components in Observerable(). I would love to get the best of both worlds and have elegant jsx components with the proxy based Vue reactivity.

avatar
Apr 16th 2022

That's not supported right now, indeed. If no runtime props are declared, then ($)props are empty - and everything you pass to that component will be in context.attrs.

There has been some discussion about how we could make something like what you expect possible here:

https://github.com/vuejs/rfcs/discussions/282

But it has been going nowhere concrete yet.

I'll close this issue in favor of the RFC discussion.

What you can explore for your specific scenario though is:

const MyComp = Vue.defineComponent((p: { name: string }) => {
    return <div>{p.name}</div>;
});

MyComp.props = ['name']
avatar
Apr 16th 2022

Ok, that is basically what I did by introducing this helper function:

function Component<T>(props: string[], setup: T): T {
    let r = Vue.defineComponent(setup);
    r.props = props;
    return r;
}
avatar
Apr 16th 2022

@LinusBorg since all props are passed when you do not use defineComponent it seems like it should also work that way for consistency when using defineComponent.

avatar
Apr 16th 2022

I'm not sure what you mean when you say:

since all props are passed when you do not use defineComponent

I suspect you mix this up with functional components which are a different thing.

avatar
Apr 19th 2022

I'm not sure what you mean when you say:

since all props are passed when you do not use defineComponent

I suspect you mix this up with functional components which are a different thing.

Correct, that is what I meant (functional components). The only difference is one does not keep state, however they both allow for props to be passed but functional components do not require you to explicitly name them.

avatar
Apr 19th 2022

Stateful components do require that.

We can't change that behavior in 3.x for backwards compatibility. Most we can do is come up with a new option for enabling this on a per component Basis.

There has been some discussion about that In our RFC repo's discussions section, but it has dried up some time ago, there wasn't to much input coming.

avatar
Apr 24th 2022

I wonder if this could be enabled globally or have an alternative defineComponent that has that functionality. I personally think that setup functions should be stateful without wrapping them in a function and have functional components require the extra step. Since so many people are using typescript and jsx I think that making that feel very natural in Vue should be a goal.