1

I created the following functional component using render method:

import Vue from "vue"

const { render, staticRenderFns } = Vue.compile(`<div>Hello World</div>`)

Vue.component("HelloWorld", {
    functional: true,
    render,
    staticRenderFns
})

And then in App.vue:

<template>
    <div id="app">
        <HelloWorld />
    </div>
</template>

<script>
export default {
    data() {
        return {
            compiled: false
        }
    }
}
</script>

<style>
</style>

And I get the error:

_c is not defined.

Am I doing something wrong here?

Axel
  • 4,365
  • 11
  • 63
  • 122
  • See this - https://stackoverflow.com/questions/44369839/dynamically-insert-child-components-inside-vuejs2-data-without-compile-or-abus you need to import your component – sugars Nov 14 '19 at 08:47
  • Import my component? But it's already declared as a global component. And also, this issue is only with the functional component. Normal component works fine i.e. if I remove `functional: true` it works fine. – Axel Nov 14 '19 at 08:55
  • 1
    How about: https://stackoverflow.com/questions/57901607/dynamically-render-vue-template/57901736#57901736 – webnoob Nov 14 '19 at 13:57
  • 2
    @webnoob Damn that's useful. Thank you very much. Although not sure about functional component. – Axel Nov 15 '19 at 03:43

3 Answers3

0

As far as I'm aware, the render functions generated by Vue.compile cannot be used to render a functional component.

Decade Moon
  • 32,968
  • 8
  • 81
  • 101
  • Oh crap! That's a bummer. Is there any way to build functional component by passing template string? – Axel Nov 14 '19 at 10:52
  • I don't think so. The template compiler bundled with Vue is not able to compile functional templates. I believe only the compiler provided with `vue-loader` can do this at build time. – Decade Moon Nov 14 '19 at 23:19
  • May I ask why you require the use of `Vue.compile`? Maybe there's a better solution to your problem. – Decade Moon Nov 14 '19 at 23:20
  • Actually I fetch html from the server and render it as a Vue component. – Axel Nov 15 '19 at 03:42
  • Is what you're fetching plain HTML or is it a Vue template? If it's sanitized HTML then you can just use `v-html` to render it. – Decade Moon Nov 15 '19 at 11:22
  • HTML is sanitized. User is allowed to create dynamic components by themselves. They define id and html and I use these to bake a component and therefore user can write for example to render this component. – Axel Nov 15 '19 at 12:12
0

I think the closest thing to creating a functional component from a template string would involve parsing the string to get the element type and attributes and render as:

Vue.component("hello-world", {
      functional: true,
      render: function(createElement, context) {
        return createElement(
          "div",
         'example text'         
        );
      }
});
MJ_Wales
  • 873
  • 2
  • 8
  • 20
0

As Decade Moon already mentioned, render functions returned by Vue.compile cannot be used as render function in functional component. Reason for that becomes clear when you inspect the signature of the function returned by Vue.compile:

const render: (createElement: any) => VNode

As you can see, function is missing second argument, which is required for render functions of functional components:

render: (createElement: CreateElement, context: RenderContext<Record<never, any>>) => VNode

Functional components are instanceless. That means no this context - that's why additional context parameter is needed to carry props\listeners etc.

Also if you look at this post on Vue forum:

The render function created by compile() relies on private properties of the component. To have access to those properties, the method has to be assigned to a property of the component(so it has access to those properties via this)

However that doesn't mean you can't create functional component with template. You can, you are just not able to use Vue.compile to pass template text dynamically. If you are fine with static template, you can do it like this:

// component.vue

<template functional>
  <div>Hello World</div>
</template>

<script>
export default {
  name: "hello"
};
</script>

...and use the component like any other SFC (single file component = VUE file)

If you need dynamic template text, just use non-functional component instead...

Michal Levý
  • 33,064
  • 4
  • 68
  • 86