Vue: [2.0] Templates for functional components

Created on 18 Oct 2016  ·  34Comments  ·  Source: vuejs/vue

I'd like to be able to write templates and .vue files for functional components the same way as standard components.

I made a proof-of-concept in this fiddle, but it's quite hacky. Maybe the template compiler could have a functional option to make the resulting functions more adapted to the context object and not this.

It would look like this:

Vue.component('test', {
  functional: true',
  props: ['msg'],
  template: `<div>
    <h1>{{props.msg}}</h1>
    <h2>Static content</h2>
    <span v-for="n in 10">{{n}} </span>
    <button @click="console.log('click', props.msg)"><slot></slot></button>
  </div>`,
});

Or:

<template>
  <div class="test">
    <h1>{{props.msg}}</h1>
    <h2>Static content</h2>
    <span v-for="n in 10">{{n}} </span>
    <button @click="console.log('click', props.msg)"><slot></slot></button>
  </div>
</template>

<script>
export default {
  functional: true,
  props: ['msg'],
}
</script>

<style scoped>
.test {
  margin: 12;
}
</style>
feature request

Most helpful comment

It is coming soon.

All 34 comments

We already have this as an option on our roadmap. However, we will pospone this until 2.0 is out of the current post-release phase and all work we have left in the ecosystem for 2.0 is done, because this will involve a considerable amount of work to get right, tested and so on (also, making vue-loader/vueify work with it etc. pp.)

Thanks for the PoC, seems helpful!

Yes please.
I was looking at exactly that. For me, render functions are too overwhelming and "feels" disjointed from the overall feel of single file component.

What would be most useful to me would be to scope css on to functional components.

Can we get a status update on this functional single file component? I am coming from React and missing this quite a bit.

It is coming soon.

Can anyone explain for a n00b what its new with this against what we have now?

You will be able to create functional components with .vue files like this:

<template functional>
  <div class="test">
    <h1>{{props.msg}}</h1>
    <h2>Static content</h2>
    <span v-for="n in 10">{{n}} </span>
    <button @click="console.log('click', props.msg)"><slot></slot></button>
  </div>
</template>

<script>
export default {
  props: ['msg'],
}
</script>

<style scoped>
.test {
  margin: 12;
}
</style>

Ahh ok thanks!!

That looks great. Any idea of the timeframe for when this feature will be released?

This is going to make functional components so much easier to use!

any updates on this topic ? will it be part of the 2.3 release ?

@Akryum Do you know the status of this issue? It seems like it's been in limbo for months. Is there anything we can do to help move this along?

/ping @blake-newman

Are there any news about this feature?

Seems work was started on this in february: https://github.com/vuejs/vue/tree/feature/fn-templates

Is there any update on this? It has been open a while now - is there anything that can be done to help move this issue?

@Akryum since your teaser back in February, this has seemed dead in the water. @blake-newman I see you were pinged a few months ago, do you have any information on this issue?

I'm sorry if this is getting annoying, I'd just really like to know how we can make this happen :)

@scottbedard I was working on it, there was a few hidden gotchas. However, these could just be documented as unusable features. The work was done quite a while ago and unfortuently doesn't map to the current state of the rendering system so work will need to be done.

@vuejs/collaborators What is you opinion on this feature overall, is the development effort and additional cost to the core worth this feature?

I think if it's a nice to have feature, since the default way to write components is using the templates. And IMHO decoupling all the rendering functions from the components (used in the templates compiler) would be great.

The problem is that the scope of using templates functionally is limiting, much more than using JSX/Render functions. A

I think at the point of building functional components, the constraints and design patterns don't fit a template model. This feature requires a small amount of extra runtime (https://github.com/vuejs/vue/commit/f63203310f01e9f0813e0316c308f9f21d0ee717#diff-4d479bb000ed54582de8e4cd8318ef64R157) and will never have the same performance as pure render functions.

Enabling this feature will assume better performance, comparative to pure render functions this is not true. My stance on the feature at the moment, is that it will only empower templates to be used functionality but gives no true reward.

Also, it would be nice to have scoped style support for functional components but it may be unrelated.

That is unrelated, i believe that is working. I did work on that before. Unless there is a regression?

Vue的函数式组件相对于React来说略显丑陋,template远不如jsx更加函数式,或许可以借用vue-loader来进行转化处理,希望可以像这样:

<script functional>
const DumbCmp = props => (
  <Button>{props.label}</Button>
);

export default DumbCmp;
</script>

actually, some guys have done this serval months ago https://github.com/nickmessing/babel-plugin-jsx-vue-functional

Yes, Vue 2.5 + vue-loader 13.3 will have proper support for template compilation, scoped CSS and hot-reload for functional components :)

Is it possible to $emit from functional components?

Unless I'm mistaken, the short answer is no. A functional component is not an instance, and therefore has no methods.

Through some hackery, I believe you actually can emit. The context object the render fn receives contains a parent which should always be a vue instance. You could choose to context.parent.$emit() or context.parent.$root.$emit() to take a more global approach. As you can see, this is not event emitting from the functional component, so depending on your use case, this is likely not the best solution.

Hey, I was researching into optimizing some of our Dashboard elements and making an SFC component functional sounds awesome, but I wont be able to have any methods or computed props there, right?
If I use a render function or JSX, I can at least define those inside the render function it self, correct?

Is it possible to $emit from functional components?

You can access the listeners object on the functional context. For example:

<my-functional-component @request-something="onRequestSomething" />

Call the listener like a method inside my-functional-component:

listeners['request-something'](42)

If I use a render function or JSX, I can at least define those inside the render function it self, correct?

Yes.

@Akryum thanks. Larger, more template heavy func components might be better off with JSX because standard render functions would make things a bit harder to read. A more advanced tutorial on these would be really sweet :)

you don't need to use a render function with functional components anymore.
You can use templates

On Fri, Jan 5, 2018 at 4:53 AM, Dobromir Hristov notifications@github.com
wrote:

@Akryum https://github.com/akryum thanks. Larger, more template heavy
func components might be better off with JSX because standard render
functions would make things a bit harder to read. A more advanced tutorial
on these would be really sweet :)


You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/vuejs/vue/issues/3977#issuecomment-355514921, or mute
the thread
https://github.com/notifications/unsubscribe-auth/AACouk0kTLUHRjQDnXj2vn2v4Rq7maXOks5tHfExgaJpZM4KaIfu
.

@blocka how will you use a function to do something? instantiate a chart for example?

unless you're rendering a chart completely with vnodes, you would need a
regular component with lifecycle methods to do that

On Fri, Jan 5, 2018 at 5:41 AM, Dobromir Hristov notifications@github.com
wrote:

@blocka https://github.com/blocka how will you use a function to do
something? instantiate a chart for example?


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/vuejs/vue/issues/3977#issuecomment-355524605, or mute
the thread
https://github.com/notifications/unsubscribe-auth/AACouvWQNer0XUjuzBDHgePpZQ-D2DAWks5tHfx2gaJpZM4KaIfu
.

@Akryum Your solution works but it leaves me feeling that functional sfc templates could use a little more love. I'm in the process of re-writing several components that could have been functional from the get-go and I'm a little disappointed with the experience. The sfc already has a context that is accessible from the template for props and listeners. Couldn't these properties just be mapped to the 'root' for props and '$emit' for listeners allowing each type of sfc to work with the same api.

<template functional>
    <div @click="listeners['request-something'](42)">
        {{props.hello}}
        {{props.world}}
    </div>
</template>

<script>
export default {
    props: ["hello", "world"]
}
</script>

could become

<template functional>
    <div @click="$emit('request-something', 42)">
        {{hello}}
        {{world}}
    </div>
</template>

<script>
export default {
    props: ["hello", "world"]
}
</script>
Was this page helpful?
0 / 5 - 0 ratings