I hope you are all well. I'm currently having some issues with using a component that is inside a parent component. I tried a few things but without success...
The component ModalBoxActionArticle doesn't want to show and I have the following error message :
[Vue warn]: Failed to resolve component: ModalBoxActionArticle at
at <Home
onVnodeUnmounted=fn ref=Ref< undefined > > at
at
Could you please help me with this? Thanks in advance for your time and help.
Find below the vue View that is at the root of these components:
<template>
<div class="home">
<ImageArticle class="home__component"/>
</div>
</template>
<script>
import ImageArticle from "../components/imageArticle"
export default {
name: 'Home',
components: {
ImageArticle,
}
}
</script>
Find below the ImageArticle component (I removed the style)
<template>
<div>
<article class="postWithImage">
<ModalBoxActionArticle/>
<div class="postWithImage__1div">
<picture class="postWithImage__pictureProfile">
<img class="postWithImage__imgProfile" src="../assets/EugenieProfile.jpeg" alt="photo de profile de la personne qui a publié l'image">
</picture>
.... here I removed some html to make it more readable ....
</article>
</div>
</template>
<script>
import ModalBoxActionArticle from '../components/modalBoxActionArticle'
export default {
name: 'ImageArticle',
component : {
ModalBoxActionArticle
},
setup() {
console.log('%c loading ImageArticle component', 'color:green');
return {};
},
}
</script>
Last but not least find below, the component ModalBoxActionArticle that is inside the ImageArticle component
<template>
<div class="modal">
<button class="modal__btt modal__btt--alert">Signaler</button>
<button class="modal__btt">Partager</button>
<button class="modal__btt">Modifier</button>
<button class="modal__btt modal__btt--alert">Supprimer</button>
</div>
</template>
<script>
export default {
name: "ModalBoxActionArticle",
setup() {
console.log('%cloading ModalBoxActionArticle newest component', 'color:red');
return {};
},
}
</script>
In ImageArticle.vue you have defined
component : {
ModalBoxActionArticle
},
This must be like (the letter s must be at the end of the word component):
components : {
ModalBoxActionArticle
},
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
As a newbie started in vue 3, I have a question regarding the router. I am following the tutorial on Vue School. It seems okay until using the named routes and params. It renders a blank page with Uncaught (in promise) TypeError: Cannot read property 'name' of undefined in the console. What I’ve noticed is that the default code given is slightly different from the tutorial, but I think that is not the main issue. I asked on the forum as well, but no luck.
Here is the code, I’ll try to minimize the project to the workable code.
[src/main.js]
// instantiate the App
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
createApp(App).use(router).mount("#app");
[src/App.vue]
<template>
<div id="app">
<TheNavigation />
<!-- In this single page, without router-view, views cannot render -->
<router-view />
</div>
</template>
<script>
import TheNavigation from "#/components/TheNavigation"
export default {
name: "app",
components: {
TheNavigation
},
}
</script>
[src/views/Home.vue]
<template>
<div class="home">
<h1>All Destination</h1>
<div class="destinations">
<div v-for="destination in destinations" :key="destination.name">
<!-- the named routes will link to the components, and its params can access the properties -->
<router-link :to="{ name:'DestinationDetails', params: { id:destination.id } }">
<h2>{{ destination.name }}</h2>
</router-link>
<figure>
<router-link :to="{ name:'DestinationDetails', params: { id:destination.id } }">
<img :src="require(`#/assets/${destination.image}`)" :alt="destination.name">
</router-link>
</figure>
</div>
</div>
</div>
</template>
<script>
// # is an alias to /src
import store from "#/store.js"
export default {
name: "home",
components: {},
data() {
return {
destinations: store.destinations
}
}
};
</script>
[src/views/DestinationDetails.vue]
<template>
<!-- should render the id -->
<!-- <h2>The destination is: {{ this.$route.params.id }}</h2> -->
<h2>The destination is: {{ $route.params.id }}</h2> <!-- turn out to be the correct way -->
<section class="destination">
<h1>{{ destination.name }}</h1> <!-- throw error, but ok in the tutorial -->
<div class="destination-details">
<img :src="require(`#/assets/${destination.image}`)" :alt="destination.name">
</div>
</section>
</template>
<script>
import store from '#/store.js'
export default({
data() {
return {
// pass the route id to use dynamic routing in the router/index.js file
destinationId:this.$route.params.id
}
},
computed: {
destination() {
return store.destinations.find(
destination => destination.id === this.destinationId
)
}
}
})
</script>
[src/router/index.js]
import { createRouter, createWebHashHistory } from "vue-router";
import Home from "../views/Home.vue";
const routes = [
{
path: "/",
name: "home",
component: Home,
},
{
path: "/brazil",
name: "brazil",
component: () => import(/* webpackChunkName: "brazil" */ '#/views/Brazil')
},
{
path: "/details",
name: "DestinationDetails",
component: () => import(/* webpackChunkName: "DestinationDetails */ '#/views/DestinationDetails')
}
];
const router = createRouter({
history: createWebHashHistory(),
routes,
});
export default router;
[src/views/Brazil.vue]
<template>
<div>
<h2>
Brazil
</h2>
</div>
</template>
[src/store.js]
// shrink down to have basic information
export default {
destinations: [
{
name: "Brazil",
slug: "brazil",
image: "brazil.jpg",
id: 1
} ]
}
Edit1
Thank #Boussadjra Brahim for the route issue, it should be $route.params.id instead of this$route.params.id.
DestinationDetails.vue?d5a2:2 Uncaught (in promise) TypeError: Cannot read property 'name' of undefined
at Proxy.eval (DestinationDetails.vue?d5a2:2)
at renderComponentRoot (runtime-core.esm-bundler.js?5c40:1166)
at componentEffect (runtime-core.esm-bundler.js?5c40:5201)
at reactiveEffect (reactivity.esm-bundler.js?a1e9:42)
at effect (reactivity.esm-bundler.js?a1e9:17)
at setupRenderEffect (runtime-core.esm-bundler.js?5c40:5154)
at mountComponent (runtime-core.esm-bundler.js?5c40:5113)
at processComponent (runtime-core.esm-bundler.js?5c40:5071)
at patch (runtime-core.esm-bundler.js?5c40:4673)
at componentEffect (runtime-core.esm-bundler.js?5c40:5274)
Now the issue remains in the DestinationDetails that destination.name is undefined but successful in the tutorial. I apologize for re-ordering and re-editing the post.
#Woden within the Vue template you can leave out the this keyword.
The same applies to your data properties, computed properties, and methods.
The Vue docs are great. Here's a link to the template syntax which explains the above.
Build your component using the defineComponent function to get the global properties inference:
<script>
import store from '#/store.js'
import {defineComponent} from 'vue'
export default defineComponent({
computed: {
destinationId(){
return this.$route.params.id
},
destination() {
return store.destinations.find(
destination => destination.id === this.destinationId
)
}
}
})
</script>
I know that we can simply show the component output with <ComponentName/> inside the template,
but how do we access ComponentName html output outside the template like in data, methods, or during mounted
e.g. components/Test.vue
<template>
<div>I'm a test</div>
</template>
in another vue file pages/ViewTest.vue
import Test from '~/components/Test.vue'
export default {
components: {Test},
data() {
return {
test: Test
}
},
mounted: function() {
console.log( Test ) // Output is Test Component Object
console.log( this.test ) // Output is Test Component Object
}
}
The object from console log output seems to contain a lot of information and I can even see a render property from the object although when I try console.log( Test.render() ) its giving me error
So My question is how can I get the <div>I'm a test</div> from outside the template?
Appreciate any help or guidance
EDIT
I'm using vue-material-design-icons package for generating different svg icons,
and I can use it like below
<template>
<MapMarkerRadius/>
</template>
<script>
import MapMarkerRadius from 'vue-material-design-icons/MapMarkerRadius'
export default {
components: {MapMarkerRadius}
}
</script>
Now here's my main issue,
I have this component that generates an html
<template>
<div :class="'card'">
<div v-if="title" :class="'card-title'">
{{ title }}
</div>
<div :class="'card-content'">
<slot />
</div>
</div>
</template>
<script>
export default {
name: 'card',
props: {
title: {},
}
};
</script>
Then I'm using that card component like this on a different vue file
<template>
<card :title="'Title ' + MapMarkerRadius">
Test Content
</card>
</template>
<script>
import card from '~/components/Card'
import MapMarkerRadius from 'vue-material-design-icons/MapMarkerRadius'
export default {
components: {card, MapMarkerRadius}
};
</script>
and my problem here is that the output of the card title is Title [object]
Try to use ref in the root of the Test component like :
<template>
<div ref="test">I'm a test</div>
</template>
in other component do :
mounted: function() {
console.log( this.$refs.test )
}
No need to import the component.
The repo that you are using are single-file components that generates html through a single tag, so using
import MapMarkerRadius from 'vue-material-design-icons/MapMarkerRadius'
will enable you to use it in template as <map-marker-radius/>
That is why appending the string title and an object like "My Icon"+MapMarkerRadius will return the literal [object] as you've seen: "My Icon [object]"
You have 3 options to go through what you want:
Search for other repos that enable you to use easily material icons in other means;
You have access to the card component? You can use the class names of this repo instead rather than the svg version or the component itself: https://github.com/robcresswell/vue-material-design-icons/issues/12, add the class names to the props and add it to your component:
<card :title="'Title'" :icon_class="map-marker-radius">
Test Content
</card>
<div v-if="title" :class="'card-title'">
{{ title }} <div :class="icon_class"></div>
</div>
props: {
title: {},
icon_class: '',
}
You can use the MapMarkerRadius component directly in card component but only appears when you pass a certain criteria on the card component, such like:
main.vue
<template>
<card :title="'Title'" :icon="true" :icon_typename="'map-marker-radius'">
Test Content
</card>
</template>
<script>
import card from '~/components/Card'
export default {
components: {card}
};
</script>
with icon_typename as any name/keyword you'd like to use.
card.vue
<template>
<div :class="'card'">
<div v-if="title" :class="'card-title'">
{{ title }} <span v-if="icon_mmr"><map-marker-radius/></span>
</div>
<div :class="'card-content'">
<slot />
</div>
</div>
</template>
<script>
import MapMarkerRadius from 'vue-material-design-icons/MapMarkerRadius'
export default {
name: 'card',
props: {
title: {},
icon: { default: false },
icon_typename: '',
icon_mmr: false,
},
mounted(){
if (this.icon && this.icon_typename === 'map-marker-radius') this.icon_mmr = true
},
components: { MapMarkerRadius },
};
</script>
The code is far from perfect but you can go from there to optimize further.
I'm trying to wrap my head around hoe Vue.js works, reading lots of documents and tutorials and taking some pluralsight classes. I have a very basic website UI up and running. Here's the App.vue (which I'm using kinda as a master page).
(To make reading this easier and faster, look for this comment: This is the part you should pay attention to)...
<template>
<div id="app">
<div>
<div>
<CommandBar />
</div>
<div>
<Navigation />
</div>
</div>
<div id="lowerContent">
<!-- This is the part you should pay attention to -->
<template v-if="showLeftContent">
<div id="leftPane">
<div id="leftContent">
<router-view name="LeftSideBar"></router-view>
</div>
</div>
</template>
<!-- // This is the part you should pay attention to -->
<div id="mainPane">
<div id="mainContent">
<router-view name="MainContent"></router-view>
</div>
</div>
</div>
</div>
</template>
And then in the same App.vue file, here's the script portion
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import CommandBar from './components/CommandBar.vue';
import Navigation from './components/Navigation.vue';
#Component({
components: {
CommandBar,
Navigation,
}
})
export default class App extends Vue {
data() {
return {
showLeftContent: true // <--- This is the part you should pay attention to
}
}
}
</script>
Ok, so the idea is, one some pages I want to show a left sidebar, but on other pages I don't. That's why that div is wrapped in <template v-if="showLeftContent">.
Then with the named <router-view>'s I can control which components get loaded into them in the `router\index.ts\ file. The routes look like this:
{
path: '/home',
name: 'Home',
components: {
default: Home,
MainContent: Home, // load the Home compliment the main content
LeftSideBar: UserSearch // load the UserSearch component in the left side bar area
}
},
So far so good! But here's the kicker. Some pages won't have a left side bar, and on those pages, I want to change showLeftContent from true to false. That's the part I can't figure out.
Let's say we have a "Notes" component that looks like this.
<template>
<div class="notes">
Notes
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
#Component
export default class Notes extends Vue {
data() {
return {
showLeftContent: false // DOES NOT WORK
}
}
}
</script>
Obviously, I'm not handling showLeftContent properly here. It would seem as if the properties in data are scoped only to that component, which I understand. I'm just not finding anything on how I can set a data property in the App component and then change it in a child component when that child is loaded through a router-view.
Thanks!
EDIT:
I changed the script section of the Notes component from:
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
#Component
export default class Notes extends Vue {
data() {
return {
showLeftContent: false // DOES NOT WORK
}
}
}
</script>
to:
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
#Component
export default class Notes extends Vue {
mounted() {
this.$root.$data.showLeftContent = false;
}
}
</script>
And while that didn't cause any compile or runtime errors, it also didn't have the desired effect. On Notes, the left side bar still shows.
EDIT 2:
If I put an alert in the script section of the Notes component:
export default class Notes extends Vue {
mounted() {
alert(this.$root.$data.showLeftContent);
//this.$root.$data.showLeftContent = false;
}
}
The alert does not pop until I click on "Notes" in the navigation. But, the value is "undefined".
EDIT 3:
Struggling with the syntax here (keep in mind this is TypeScript, which I don't know very well!!)
Edit 4:
Inching along!
export default class App extends Vue {
data() {
return {
showLeftContent: true
}
}
leftContent(value: boolean) {
alert('clicked');
this.$root.$emit('left-content', value);
}
}
This does not result in any errors, but it also doesn't work. The event never gets fired. I'm going to try putting it in the Navigation component and see if that works.
As it says on #lukebearden answer you can use the emit event to pass true/false to the main App component on router-link click.
Assuming your Navigation component looks like below, you can do something like that:
#Navigation.vue
<template>
<div>
<router-link to="/home" #click.native="leftContent(true)">Home</router-link> -
<router-link to="/notes" #click.native="leftContent(false)">Notes</router-link>
</div>
</template>
<script>
export default {
methods: {
leftContent(value) {
this.$emit('left-content', value)
}
}
}
</script>
And in your main App you listen the emit on Navigation:
<template>
<div id="app">
<div>
<Navigation #left-content="leftContent" />
</div>
<div id="lowerContent">
<template v-if="showLeftContent">
//...
</template>
<div id="mainPane">
//...
</div>
</div>
</div>
</template>
<script>
//...
data() {
return {
showLeftContent: true
}
},
methods: {
leftContent(value) {
this.showLeftContent = value
}
}
};
</script>
A basic approach in a parent-child component relationship is to emit events from the child and then listen and handle that event in the parent component.
However, I'm not sure that approach works when working with the router-view. This person solved it by watching the $route attribute for changes. https://forum.vuejs.org/t/emitting-events-from-vue-router/10136/6
You might also want to look into creating a simple event bus using a vue instance, or using vuex.
If you'd like to access the data property (or props, options etc) of the root instance, you can use this.$root.$data. (Check Vue Guide: Handling Edge)
For your codes, you can change this.$root.$data.showLeftContent to true/false in the hook=mounted of other Components, then when Vue creates instances for those components, it will show/hide the left side panel relevantly.
Below is one demo:
Vue.config.productionTip = false
Vue.component('child', {
template: `<div :style="{'background-color':color}" style="padding: 10px">
Reach to root: <button #click="changeRootData()">Click me!</button>
<hr>
<slot></slot>
</div>`,
props: ['color'],
methods: {
changeRootData() {
this.$root.$data.testValue += ' :) '
}
}
})
new Vue({
el: '#app',
data() {
return {
testValue: 'Puss In Boots'
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
<h2>{{testValue}}</h2>
<child color="red"><child color="gray"><child color="green"></child></child></child>
</div>
I have a child component called goback.vue which only function is to go back one step in the navigation history. The reason why I am asking this question is because I am trying to reuse this component often in many other components and I want to be able to edit the style and template later on just one place.
This is the code of the component goback.vue:
<template>
<span #click="backOneStep">
<svg type="submit" class="arrowleft" >
<use href="../static/icons/iconsset.svg#arrowleft"></use>
</svg>
</span>
</template>
<script>
export default {
name: 'goback',
data () {
return {
}
},
methods: {
backOneStep(){
window.history.go(-1)
},
}
}
<script>
Then on my several of my parent components I am importing the child component in the following manner:
<template>
<div class="building">
<div id="title">
<goback></goback> // using the child component here
</div>
</div>
</template>
<script>
import goback from './goback.vue';
export default {
components: {
goback
},
name: 'maincomponent',
data () {
return {
}
}
},
methods: {
backOneStep(){ // do I need to repeat this here?
window.history.go(-1)
},
}
}
</script>
First, I am wondering if I need to repeat the method on all parent components or if I can just write it on my child component.
Second, I am getting an error message:
[Vue warn]: Property or method "backOneStep" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://v2.vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.
found in
<Goback> at src/components/goback.vue
<Depts> at src/components/depts.vue
<App> at src/App.vue
<Root>
Note: I have carefully read the link but I am still stuck
Immediately following the previous error message I am also getting this error message:
[Vue warn]: Invalid handler for event "click": got undefined
found in
<Goback> at src/components/goback.vue
<Depts> at src/components/depts.vue
<App> at src/App.vue
<Root>
Would be able to tell me what I can do to avoid this?
Is this related to props? I have tried declaring the "backOneStep" prop in the data of the goback.vue but I am not sure I have done it correctly. What am I missing here?
You can use a $emit event to tell the parent to "go back" on click in the child component:
<template>
<span #click="backOneStep">
<svg type="submit" class="arrowleft" >
<use href="../static/icons/iconsset.svg#arrowleft"></use>
</svg>
</span>
</template>
<script>
export default {
name: 'goback',
methods: {
backOneStep() {
this.$emit('back')
}
}
}
</script>
And in the parent:
<template>
<div class="building">
<div id="title">
<goback #back="window.history.go(-1)"></goback>
</div>
</div>
</template>
This did it for me as the main reason I wanted to isolate this element/function on a component was to be able to change the style of the element in one place:
The child component:
<template>
<span v-on:click="$emit('back')">
<svg type="submit" class="arrowleft" >
<use href="../static/icons/iconsset.svg#arrowleft"></use>
</svg>
</span>
</template>
<script>
export default {
name: 'goback',
data () {
return {
}
}
}
<script>
<style scoped>
// enter styles here
</style>
On the parent:
<template>
<div class="building">
<div id="title">
<goback #back="window.history.go(-1)"></goback>
</div>
</div>
</template>
<script>
import goback from './goback.vue';
export default {
components: {
goback
},
methods: {
backOneStep(){
window.history.go(-1)
},
}
}
</script>
In a Vue 2.0 app, let's say we have components A, B and C.
A declares, registers and uses B
Is it possible to pass C from A to B?
Something like this:
<template>
<div class="A">
<B :child_component="C" />
</div>
</template>
And use C in B somehow.
<template>
<div class="B">
<C>Something else</C>
</div>
</template>
The motivation: I want to create a generic component B that is used in A but receives from A its child C. Actually A will use B several times passing different 'C's to it.
If this approach is not correct, what is the proper way of doing it in Vue?
Answering #Saurabh
Instead of passing as props, I tried the suggestion inside B.
<!-- this is where I Call the dynamic component in B -->
<component :is="child_component"></component>
//this is what I did in B js
components: {
equip: Equipment
},
data () {
return {
child_component: 'equip',
_list: []
}
}
Basically I'm trying to render Equipment, but the dynamic way
I get 3 errors in console and a blank page
[Vue warn]: Error when rendering component at /home/victor/projetos/tokaai/public/src/components/EquipmentFormItem.vue:
Uncaught TypeError: Cannot read property 'name' of undefined
TypeError: Cannot read property 'setAttribute' of undefined
Apparently I'm doing something wrong
Summing up:
<!-- Component A -->
<template>
<div class="A">
<B>
<component :is="child_component"></component>
</B>
</div>
</template>
<script>
import B from './B.vue';
import Equipment from './Equipment.vue';
export default {
name: 'A',
components: { B, Equipment },
data() {
return { child_component: 'equipment' };
}
};
</script>
<!-- Component B -->
<template>
<div class="B">
<h1>Some content</h1>
<slot></slot> <!-- Component C will appear here -->
</div>
</template>
You can use special attribute is for doing this kind of thing. Example of dynamic component and its usage can be found here.
You can use the same mount point and dynamically switch between multiple components using the reserved element and dynamically bind to its is attribute.
Here's how is can be used with either an imported component or one passed as a prop:
<template>
<div class="B">
<component :is="myImportedComponent">Something</component>
--- or ---
<component :is="myPassedComponent">Something else</component>
</div>
</template>
<script>
import myImportedComponent from "#/components/SomeComponent.vue"
export default {
props: {
myPassedComponent: Object
},
components: {
myImportedComponent
},
}
</script>
Here's solution to forward custom component through props of another component
:is is special attribute and it will be used to replace your actual component and it will be ignored if you try to use it as a prop in your component. Luckily you can use something else like el and then forward this to component like so:
<template>
<div>
<component :is="el">
<slot />
</component>
</div>
</template>
<script>
export default {
name: 'RenderDynamicChild',
props: {
el: {
type: [String, Object],
default: 'div',
},
},
}
</script>
Any valid element you use in el attribute will be used as a child component. It can be html or reference to your custom component or div by default as specified in component declaration.
Passing custom component to prop is little bit tricky. One would assume you declare in a components property of parent component and then use it for el attribute but this doesn't work. Instead you need to have your dynamic component in data or computed property so you can use it in a template as a prop. Also note AnotherComponent doesn't need to be declared in components property.
<template>
<RenderDynamicChild :el="DynamicComponent">
Hello Vue!
</RenderDynamicChild>
</template>
<script>
import RenderDynamicChild from './DynamicChild';
import AnotherComponent from './AnotherComponent';
export default {
name: "ParentComponent",
components: { DynamicChild },
data() {
return {
DynamicComponent: AnotherComponent,
};
},
};
</script>
Using computed property for your dynamic component allows you to switch between components easily:
<script>
import DynamicChild from './DynamicChild';
import AnotherComponent from './AnotherComponent';
export default {
name: "ParentComponent",
components: { DynamicChild },
data() { return { count: 0 } },
computed: {
DynamicComponent() {
return this.count % 2 > 1 ? AnotherComponent : 'article';
},
},
};
</script>
Increase this.count to alternate between AnotherComponent and simple article html element.
Maybe it's too late to answer this question. But I think it could help others with this same issue.
I've been looking for a way to pass components throw others in vue, but it looks that VUE3 have a approach for that using named slots:
Here it's the documentation about that:
https://v3.vuejs.org/guide/component-slots.html#named-slots
Basically you can have:
<template>
<div class="A">
<slot name="ComponentC"></slot> <!-- Here will be rendered your ComponentC -->
</div>
<div class="A">
<slot name="ComponentD"></slot> <!-- Here will be rendered your ComponentD -->
</div>
<div class="A">
<slot></slot> <!-- This is going to be children components -->
</div>
</template>
And from your B component
<template>
<div class="B">
<A>
<template v-slot:ComponentC>
<h1>Title of ComponentC </h1>
</template>
<template v-slot:ComponentD>
<h1>Title of ComponentD </h1>
</template>
<template v-slot:default>
<h1>Title of child component </h1>
</template>
</A>
</div>
</template>
If you would like to use another component within your functional component you can do the following:
<script>
import Vue from 'vue'
import childComponent from './childComponent'
Vue.component('child-component')
export default {}
</script>
<template functional>
<div>
<child-component/>
</div>
</template>
Reference:
https://github.com/vuejs/vue/issues/7492#issue-290242300
If you mean Dynamically importing a component in a parent component, so yes, you can do that in Vue3 using:
<component :is="child_component" />
but to render "child_component" itself dynamically, you can use
import { defineAsyncComponent } from 'vue'
const AsyncComp = defineAsyncComponent(() =>
import('./components/MyComponent.vue')
)
Let me give you an example:
let's say you have several multiple child components (ChildA, ChildB, ChildC) that you want to load dynamically based on what you pass to the parent component (Parent), so the Parent component will be something like this:
Parent
<script setup lang="ts">
import { defineAsyncComponent } from 'vue';
const props = defineProps<{
childComponent?: string;
}>();
const AsyncComp = defineAsyncComponent(() =>
import(`./${props.childComponent}.vue`)
)
</script>
<template>
<component :is="AsyncComp"/>
</template>
and then you can call the Parent component dynamically wherever you want like this:
<Parent :childComponent="child-a"/>
<Parent :childComponent="child-b"/>
<Parent :childComponent="child-c"/>
For a better explanation, you can check this article:
https://medium.com/#pratikpatel_60309/dynamic-importing-component-templates-with-vue-js-78d2167db1e7