Open terrierscript opened 6 years ago
Ran into exact same issue here, nice workaround!!!
Just learning Vue and struggling with this for the past few hours! Thanks for bringing it up!
Here is another workaround, it avoids global component, but looks not pretty
<template functional>
<div>
<component :is="props.components.SomeChildren"></component>
</div>
</template>
<script>
import SomeChildren from "./SomeChildren.vue";
export default {
props: {
components: {
type: Object,
default() {
return {
SomeChildren
};
}
}
}
};
</script>
I think it's worth mentioning here that the error message is quite unintuitive. The Unkown custom element
error bubbles up to the first instance component. If for some reason the feature for local functional component registration does not get implemented, at least add a dev warning that says something to the effect of Invalid property "components" on functional component X
.
Also, as awkward as it is, registering the unknown component in the first parent instance component clears the error without polluting the global component name scope. It's a strange coupling of components though. Choose your hack for now I suppose.
@ywwhack Your workaround is great! I made some improvements. We can use injections instead of props, so that props will not be polluted, and the code looks a little prettier.
<template functional>
<div>
<component :is="injections.components.SomeChildren"></component>
</div>
</template>
<script>
import SomeChildren from "./SomeChildren.vue";
export default {
inject: {
components: {
default: {
SomeChildren
}
}
}
};
</script>
any update on implementing components option in functional components ?
The workarounds are good but that seems pretty hacky IMO especially when mentioning that <component :is="injections.components.SomeChildren"></component>
must be fore dynamic components and not for known components
parent:
// template functional
v-list
component(
:is='injections.components.myListItem'
v-for='item in props.data',
:key='item.title',
:data='item')
// script
import myListItem from './listItem'
export default {
name: 'myList',
inject: {
components: {
default: {myListItem}
}
}
}
children:
// template functional
v-list-group(v-if='Array.isArray(props.data.children)')
v-list-tile(slot='activator')
v-list-tile-content
v-list-tile-title {{props.data.title}}
my-list-item(
v-for='item in props.data.children',
:key='item.title',
:data='item')
v-list-tile(v-else)
v-list-tile-content
v-list-tile-title {{props.data.title}}
// script
export default {
name: 'myListItem'
}
app:
// template
#app
my-list(:data='list')
// script
import myList from './list'
export default {
name: 'App',
components: {myList},
data() {
return {
list: [
{title: 1},
{title: 2},
{title: 3},
{
title: 4,
children: [
{title: 41},
{title: 42},
{title: 43}
]
},
{title: 5}
]
}
}
}
children error: Unknown custom element multi-level functional components nesting failed. help me!~
Any ideas how to implement dynamic async components inside functional components?
E.g. functional should be simple wrapper like
<component :is="componentName" />
where componentName
is one of the dynamically imported components?
For non-functional component it looks like this:
<template>
<component :is="componentName" v-bind="$attrs"/>
</template>
<script>
const someCondition = Math.random() > 0.5
export default {
name: 'PolicyRequestInfo',
components: {
FirstDynamic: () => import('./FirstDynamic'),
SecondDynamic: () => import('./SecondDynamic')
},
computed: {
componentName() {
return SomeCondition ? 'FirstDynamic' : 'SecondDynamic'
}
}
}
</script>
For functional component I have no idea how to make it work.
The type declaration shows that, functional component of current version can't accept components
option in fact.
Of course a possible solution is to use the render function:
<script>
import SomeChildren from './SomeChildren.vue'
export default {
render (h) {
return h('div', [
h(SomeChildren),
])
}
}
</script>
Yep, it actually works with render functions. I use something like that now:
<script>
const component = Math.random() > 0.5
? () => import('./compA')
: () => import('./compB')
export default {
functional: true,
render(h, context) {
return h(component, context.data, context.children)
}
}
</script>
Would really love to see components
option being supported for functional components.
This feature would certainly extend the usefulness of functional components in a natural way. I for one had not realised that components
wasn't supported in functional components until we tried it and found out. We have a library of components as SFCs, and wanted to mark some of the simple ones with no internal state as functional.
At the moment, if a component is a SFC and has child component dependencies and we want to mark it functional, the options would seem to be:
props
or inject
and then references them with a <component :is="...">
However, in a library of many interlinked components all done as SFCs it is desirable to retain the template for consistency with the other components, and undesirable to globally register names. The workaround for all its ingenuity looks rather messy/fiddly and would require explanation for maintenance. It would be much neater just to be able to declare child components with components
exactly as for non-functional SFCs.
Fix #8143 looks good and ready to go. If there isn't a reason not to, can it be delivered? We've held off from making any of our components functional atm, and would use it right away :-)
I for one had not realised that
components
wasn't supported in functional components until we tried it and found out.
That was my experience too. I remember being quite surprised when I discovered components weren't supported in functional components. This really, really diminished the usefulness of functional components and I rarely use them because of this.
I do use JSX in my Vue projects because sometimes I need to drop down into the render function, so this isn't technically a huge issue for me, but I like to avoid JSX whenever possible.
I'm hoping Vue 3 will improve on this in some way. React already does functional components well.
an ingenious workaround described above by @ywwhack @caikan and others that loads the dependency child components using
props
orinject
and then references them with a<component :is="...">
I'm not a fan of this hack TBH. I will just stay clear of functional components until this issue is officially resolved.
I just made a SFC with <template functional>
and a components
option in the script object, and there are no complaints by the build system or during runtime.
This is with Vue 2.6.6.
Correction: After restarting the build it does not work in fact.
Is the workaround from @ywwhack / @caikan workaround still the best way to go these days? With all the mentions at the end it's hard to tell if there's an official fix.
+1. Will not be using the work around as it decreases code readability (since it cannot be found in Vue documentation). Please implement this much needed fix. Thank you
I suspect this, like some other features for functional components, will not be implemented since Vue 3 (the alpha/proposal) alleviates the whole issue by making the difference between functional and non-functional components small. See this and the following comments: https://github.com/vuejs/vue/pull/8143#issuecomment-482481117
hey @maksnester I'm working on this for a Vue 2.6.x project. I'm trying to allow the functional component to accept a name
prop to make it even more dynamic. Any clue on how I can implement your solution dynamically?
Asked on Stackoverflow too (here) if you want more details about my problem. Thanks!
As an alternative option, vue-import-loader offers support for component resolution in functional components
Still no improvements on this till now? I found a future-proof way to do it but still not happy with it:
<script>
import ChildComp from '@/components/ChildComp.vue';
export default {
components: {
ChildComp,
},
};
</script>
<template>
<component :is="$options.components.ChildComp" any-prop="value" />
</template>
@darkylmnx it's a #wontfix since Vue 3 will make functional components irrelevant, as I understood.
Oh... I see.
Le jeu. 18 juin 2020 à 22:30, andreas notifications@github.com a écrit :
@darkylmnx https://github.com/darkylmnx it's a #wontfix since Vue 3 will make functional components irrelevant, as I understood.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/vuejs/vue/issues/7492#issuecomment-646289731, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAK4HNNSMXAU3KXBWHRMYKTRXJ2NNANCNFSM4EMWWNEA .
There's RFC: https://github.com/vuejs/rfcs/blob/master/active-rfcs/0007-functional-async-api-change.md
We will just rewrite our functional components as plain functions, that's all, much better, imo.
Version
2.5.13
Reproduction link
NG pattern (functional) https://codesandbox.io/s/004vv2onw0
OK pattern (no functional) https://codesandbox.io/s/q9k5q8qq56
Steps to reproduce
I found can't use
components
option whenfunctional
single file component.It's occure
Unknown custom element
.What is expected?
Not occure
Unknown custom element
and use child componentWhat is actually happening?
It's occure
Unknown custom element
In workaround, it not occure when use
Vue.component
.