Loading dynamic components asynchronously in Vue 3 allows for improved performance and enhanced user experience

My goal is to dynamically display components based on their type. Here's how I'm approaching it:

I have several similar components that should show different content depending on their type. Using the defineAsyncComponent method, I can easily import and use these components. For example:

const CheckBoxControl = defineAsyncComponent(
  () => import('@/components/editor/controls/CheckBoxControl.vue'),
);

While this method works fine, I end up with a long list of imported components, which is not ideal. To address this, I've wrapped the defineAsyncComponent inside an arrow function like so:

const loadComponent = async (type: string) =>
  defineAsyncComponent(
    () =>
      import(
        `@/components/editor/controls/${type[0].toUpperCase()}${type.substring(
          1,
        )}Control.vue`
      ),
  );

In the template, I can then render the component using

<component :is="renderComponent(control.type)" />

However, this approach triggers the following warning: "[Vue warn]: Component is missing template or render function." Even awaiting the defineAsyncComponent method doesn't resolve the issue.

What am I doing wrong? How can I dynamically import and render these components?

Update

These are the possibilities for the control.type attribute:

  • checkbox
  • date
  • email
  • number
  • radio
  • range
  • select
  • textarea
  • text

Update 2

Here is my current code that is functioning correctly:

const CheckBoxControl = defineAsyncComponent(
  () => import('@/components/editor/controls/CheckBoxControl.vue'),
);

// Repeat above pattern for other control types

const loadComponent = (type: string) => {
  switch (type) {
    case 'checkbox':
      return CheckBoxControl;
    // Add cases for other control types here
  }
};

Update 3

My setup involves using Vite as the build tool, version 2.9.5. I'm also using Vue version 3.2.33 and TypeScript version 4.6.3.

Answer №1

Big thanks to @Estus Flask for the assistance :)

The issue I encountered was due to my attempt to import it using the @ alias. The solution came when I revised my approach like so:

const loadComponent = (type: string) =>
  defineAsyncComponent(
    () =>
      import(
        `./controls/${type[0].toUpperCase()}${type.substring(1)}Control.vue`
      ),
  );

This adjustment resolved the problem.

I'm puzzled as to why the @ alias didn't work in this scenario, especially since it functions correctly in

const CheckboxControl = defineAsyncComponent(
  () => import('@/components/editor/controls/CheckboxControl.vue'),
);

If anyone can shed light on this discrepancy, it would be greatly appreciated.

Answer №2

async requires the function to return a promise object, but in this case a component is needed. It should be a standard function:

const createComponent = (type: string) => ...

The correct way to handle promises from import is using defineAsyncComponent.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the best way to store tests away from the source directory in Vite projects?

Executing npm init vue@latest using the specified setup https://i.stack.imgur.com/2c7XX.png results in a Vitest spec file being created in the src directory. I am curious as to why Cypress e2e tests are placed in a separate directory while Vitest unit te ...

"What is the best way to apply multiple filters to an array in a React

Is there a way to incorporate dropdown menus along with search text input for filtering an array in React? I would like to give users the option to select a location and then search for specific results within that location. Any suggestions on how to ach ...

Encountering a situation where d3.events is returning null within Angular 2 TypeScript code

Seeking to enhance my d3 maps with tooltips, I came across a helpful code snippet at this link However, upon implementing the same code in an Angular 2 TypeScript file, an error emerged: Error: Cannot read property 'transition' of undefined Th ...

Connect an attribute to an image source in pug using vue

In my component, I have created two props: 'iconSrc' for the image source that I want to keep and 'icon' as a boolean condition. The purpose is to only display the image if the condition is true. props: { iconSrc: { type: Stri ...

What is the most effective way to retrieve data from a URL and process it using reactjs?

Looking to consume JSON data from a URL, here is an example of the JSON structure: { "results": [ ... ], "info": { ... } } I aim to display the fetched data as a component property. What is the most efficient way to achie ...

Transform a Vue JS Typescript object into an array and then back into an object through iteration

Having an object that contains an array of objects, I am looking to extract the data from each object in the array to show the opening hours. I have successfully accessed each key value within a for loop in the code snippet. However, I am unsure about how ...

The click event triggered by the onclick clone/function may not always activate the click handler

As a newcomer in the JavaScript domain, I am encountering an issue where the first clone created after clicking 'add more' does not trigger my click me function. However, every subsequent clone works perfectly fine with it. What could be causing ...

When trying to gather multiple parameters using @Param in a NestJS controller, the retrieved values turn out

Can someone help me understand why I am struggling to retrieve parameters using the @Param() decorators in my NestJS controller? These decorators are defined in both the @Controller() decorator argument and the @Get() argument. I am relatively new to Nest ...

Using a function that is passed down from a parent component into a child component

One of my components has a parent-child relationship: <select-school-type placeholder="Filter by school type" @selected="getSchools"></select-school-type> I want the "getSchools" method to be triggered when the user changes ...

Creating a project using TypeScript, NodeJs, and mongoose-paginate-v2 seems like an impossible

Having trouble setting up mongoose-paginate-v2 in my current project. I'm facing three errors while trying to compile my code. Any ideas on why this is happening? Many thanks. node_modules/@types/mongoose-paginate-v2/index.d.ts:34:21 - error TS2304: ...

Unable to use console log in shorthand arrow function while working with Typescript

When debugging an arrow function in JavaScript, you can write it like this: const sum = (a, b) => console.log(a, b) || a + b; This code will first log a and b to the console and then return the actual result of the function. However, when using TypeSc ...

Is it possible to alter the video dynamically according to the state in Vuex?

I am working on a small web application that mimics the appearance of FaceTime. My goal is to switch between video elements by clicking a "Next" button, which will update a value in Vuex and swap out the video accordingly. I initially attempted this appr ...

Guide on converting a JSON object into a TypeScript Object

I'm currently having issues converting my JSON Object into a TypeScript class with matching attributes. Can someone help me identify what I'm doing wrong? Employee Class export class Employee{ firstname: string; lastname: string; bi ...

Enhance your Vue.js 3 tables with sorting, filtering, and pagination capabilities using this custom component

After extensive research, I am still unable to find an updated Vue.js 3 component that offers sorting, filtering, and pagination for tables without the need for additional requests to a backend API. The options I have come across either seem outdated, are ...

Tips for creating a vertical scrollbar within a row component

Is there a way to create a scrollable parent v-row with a child v-row overflowing with content so that I can nest another v-row inside the v-col and ensure it remains within the scroll element? <v-row> <v-col> <v-row> <p ...

Issue encountered when working with Next Auth and TypeScript: The argument type 'string | undefined' cannot be assigned to the parameter type 'string | Buffer'

Encountering a TypeScript error that states: "Argument of type 'string | undefined' is not assignable to parameter of type 'string | Buffer'." An attempt to integrate NextAuth into a Next.js 14 application and configure logi ...

The function database is not defined in firebase_compat_app__WEBPACK_IMPORTED_MODULE_0__.default

Encountering an error message when attempting to connect my app to Firebase: firebase_compat_app__WEBPACK_IMPORTED_MODULE_0__.default.database is not a function After some testing, it seems the issue only arises when trying to connect to the database. The ...

Tips for utilizing pre-installed validation regulations in VeeValidate 4?

Currently transitioning from Vue 2 to Vue 3, I am interested in utilizing VeeValidate 4 for my validations. However, it seems that the documentation does not provide any information on using built-in rules such as min, max, alpha_spaces, etc. Do I need to ...

Encountering a snag when trying to load JavaScript within an HTML document

I encountered an error while trying to load an HTML file in the JavaScript console of the Brave browser. The error message reads: require.js:5 Uncaught Error: Module name "constants.js" has not been loaded yet for context: _. Use require([]) https://requir ...

Angular's DecimalPipe will truncate any strings that exceed 10 digits

Using the decimal pipe to format numbers in an input field value| number:'0.0-6': 'en-us' When working with numbers containing more than 10 digits, it displays as follows: For 11111111111.123456, it formats to 11,111,111,111.123455 ...