3
Author: Apoorv Tyagi
Translator: Frontend Xiaozhi
Source: dev

If you have dreams and dry goods, search for [Daily Move to the World] still doing dishes in the early morning.

This article GitHub https://github.com/qq449245884/xiaozhi has been included, the first-line factory interview complete test sites, materials and my series of articles.

Using Vue3's DefileAsyncComponent function allows us to lazily load components. To put it bluntly, we create an asynchronous component that will only be loaded when needed.

This is a great way to improve the initial page load, because our application will be loaded in smaller chunks instead of having to load every component when the page loads.

image.png

In this article, we will learn defineAsyncComponent and learn an example of lazy loading pop-up windows.

What is defineAsyncComponent?

const AsyncComp = defineAsyncComponent(
  () =>
    new Promise((resolve, reject) => {
      resolve({
        template: '<div>I am async!</div>'
      })
    })
)

defineAsyncComponent can accept a factory function Promise The resolve callback of the Promise should be called after the server returns the component definition. You can also call reject(reason) to indicate that the load failed.

defineAsyncComponent can be imported from vue and use:

import { defineAsyncComponent } from "vue" 

// simple usage 
const LoginPopup = defineAsyncComponent(() => import("./components/LoginPopup.vue"))

This is defineAsyncComponent easiest method for higher-order usage, defineAsyncComponent can accept an object:

const AsyncPopup = defineAsyncComponent({ 
  loader: () => import("./LoginPopup.vue"),
   // 加载异步组件时要使用的组件
  loadingComponent: LoadingComponent,
   // 加载失败时要使用的组件
  errorComponent: ErrorComponent, 
  // 在显示 loadingComponent 之前的延迟 | 默认值:200(单位 ms)
  delay: 1000, 
  // 如果提供了 timeout ,并且加载组件的时间超过了设定值,将显示错误组件
  // 默认值:Infinity(即永不超时,单位 ms)
  timeout: 3000 
})

The basics have been introduced, then, let's make an example.

Use defineAsyncComponent to load Popup components asynchronously

In this example, we will use a login popup triggered by clicking a button.

We don't need our application to load this component every time it loads, because it is only needed when the user performs a specific action.

The following is the implementation of the login component:

// LoginPopup.vue
<template>
   <div class="popup">
       <div class="content">
           <h4> Login to your account </h4>
           <input type="text" placeholder="Email" />
           <input type="password" placeholder="Password" />
           <button> Log in </button>
       </div>
   </div>
</template>

<script>
</script>

<style scoped>
.popup {
    position: fixed;
    width: 100%;
    top: ; 
    left: ;
    height: 100%;
    background-color: rgba(, , , 0.2);
    display: flex;
    justify-content: center;
    align-items: center;
}
.content {
   min-width: 200px;
   width: 30%;
   background: #fff;
   height: 200px;
   padding: 10px;
   border-radius: 5px;
}
input[type="text"], input[type="password"] {
    border: ;
    outline: ;
    border-bottom: 1px solid #eee;
    width: 80%;
    margin:  auto;
    font-size: 0.5em;
}
button {
   border: ;
   margin-top: 50px;
   background-color:#8e44ad;
   color: #fff;
   padding: 5px 10px;
   font-size: 0.5em;
}
</style>

image.png

Import it in other components:

<template>
  <button @click="show = true"> Login </button>
  <login-popup v-if="show" />
</template>

<script>
import LoginPopup from './components/LoginPopup.vue'
export default {
  components: { LoginPopup },
  data() {
    return {
      show: false
    }
  }
}
</script>

We can use defineAsyncComponent and load it only when needed (use v-if to switch when the button is clicked).

<!-- Use defineAsyncComponent  -->
<template>
  <button @click="show = true"> Login </button>
  <login-popup v-if="show" />
</template>

<script>
import { defineAsyncComponent } from 'vue'
export default {
  components: { 
    "LoginPopup" : defineAsyncComponent(() => import('./components/LoginPopup.vue'))
  },
  data() {
    return {
      show: false
    }
  }
}
</script>

This usage looks similar to the above, no hurry, we open the console at F12

If we don't use defineAsyncComponent , once our page loads, we will see our application get LoginPopup.vue from the server. Although in this example, the performance problem is not so serious, but if we have dozens of components to do so, the performance will be more or less affected.

image.png

However, if we use defineAsyncComponent view the same tag, we will notice that when our page loads, LoginPopup.vue is not available because it has not been loaded yet.

image.png

But if we toggle the button, we can see it:

image.png

This helps us achieve the best performance. We only want to load the required components when our page is initially loaded. Conditionally rendered components are often not needed when our page loads, so why let our application load them?

How to use it with the asynchronous setup method?

Regardless of whether we use defineAsyncComponent to load asynchronously, any setup method must be packaged <Suspense>

In short, creating an asynchronous setup function is one of our options, allowing our components to wait for some API calls or other asynchronous operations before rendering.

The following is a setup , using setTimeout() simulate API calls

<template>
   <div class="popup">
       <div class="content">
            <p> Loaded API: {{ article }} </p>
           <h4> Login to your account </h4>
           <input type="text" placeholder="Email" />
           <input type="password" placeholder="Password" />
           <button> Log in </button>
       </div>
   </div>
</template>

<script>
const getArticleInfo = async () => {
     // wait 3 seconds to mimic API call
    await new Promise(resolve => setTimeout(resolve, 1000));
    const article = {
        title: 'My Vue 3 Article',
        author: 'Matt Maribojoc'
    }
    return article
}
export default {
    async setup() {
        const article = await getArticleInfo()
        console.log(article)
        return {
            article
        }
    }
}
</script>

We can import it into the component with or without defineAsyncComponent

import LoginPopup from './components/LoginPopup.vue'

// OR 

const LoginPopup = defineAsyncComponent(() => import("./components/LoginPopup.vue"))

But if we want it to be rendered in our template, we need to wrap it in a Suspense element. This will wait for our setup parse, and then try to render our component.

Suspense is that we can use slots and templates to display the fallback content. The fallback content will be displayed until the setup function is resolved and our component is ready to render. Please note that v-if has been moved from the component itself to our Suspense component, so all rollback content will be displayed.

<template>
  <button @click="show = true"> Login </button>
  <Suspense v-if="show">
    <template #default>
      <login-popup  />
    </template>
    <template #fallback>
      <p> Loading... </p>
    </template>
  </Suspense>
</template>

Below is the running result, you will see "Loading…" , and then after 3 seconds (the hard-coded value of setTimeout

By default, we use defineAsyncComponent define all components that are Suspense .

This means that if a component has Suspense in its parent chain, it will be treated as an asynchronous dependency of that Suspense. The loading, error, delay, and timeout options of our component will be ignored, and Suspense will handle it instead.

Summarize

When building large projects with many components, defineAsyncComponent is very useful. When we use lazy loading components, we can load pages faster, improve user experience, and ultimately increase application retention and conversion rates.

I would love to know what everyone thinks of this feature. If you have used it in your application, remember to leave a comment and share it.

~End, I am Xiaozhi, what am I going to do today~


code is deployed, the possible bugs cannot be known in real time. In order to solve these bugs afterwards, a lot of time was spent on log debugging. By the way, I would like to recommend a useful BUG monitoring tool Fundebug .

Original: https://learnvue.co/2021/06/lazy-load-components-in-vue-with-defineasynccomponent/

comminicate

If you have dreams and dry goods, search for [Great Move to the World] attention to this wise brush who is still doing dishes in the early morning.

This article GitHub https://github.com/qq449245884/xiaozhi has been included, the first-line interview complete test site, information and my series of articles.


王大冶
68k 声望104.9k 粉丝