[Vue3] Lazy loading of component data

Lazy loading of component data - basic use

Goal: Optimize fresh goodies and popular recommendation modules through useIntersectionObserver

E-commerce websites, especially the homepage, have several screens of content. If you load the data of all screens and render the content of all screens, the homepage will load very slowly.

Data lazy loading: When the component officially enters the visible area, the ajax request inside the component is initiated, otherwise no data is requested

(1) Optimize fresh products

<script lang="ts" setup>
const {
    
     home } = useStore()
const target = ref(null)
const {
    
     stop } = useIntersectionObserver(target, ([{
    
     isIntersecting }]) => {
    
    
  console.log(isIntersecting)
  // isIntersecting 是否进入可视区域,true是进入 false是移出
  if (isIntersecting) {
    
    
    home.getNewList()
    stop()
  }
})
</script>

<template>
  <div class="home-new">
    <HomePanel ref="target" title="新鲜好物" sub-title="新鲜出炉 品质靠谱">
    </HomePanel>
  </div>
</template>

(2) Optimize popularity recommendation

<script lang="ts" setup>
const {
    
     home } = useStore()
const target = ref(null)
const {
    
     stop } = useIntersectionObserver(target, ([{
    
     isIntersecting }]) => {
    
    
  console.log(isIntersecting)
  // isIntersecting 是否进入可视区域,true是进入 false是移出
  if (isIntersecting) {
    
    
    home.getHotList()
    stop()
  }
})
</script>
<template>
  <HomePanel ref="target" title="人气推荐" sub-title="人气爆款 不容错过">

  </HomePanel>
</template>

Add component type to ref

Reference link: https://staging-cn.vuejs.org/guide/typescript/composition-api.html#typing-component-template-refs

<!-- App.vue -->
<script setup lang="ts">
import MyModal from './MyModal.vue'

const modal = ref<InstanceType<typeof MyModal> | null>(null)

const openModal = () => {
    
    
  modal.value?.open()
}
</script>

Component data lazy loading - encapsulation

Goal: Encapsulate component data lazy loading and reusable logic

analyze

On the home page, component data lazy loading should be used in many places. No matter which module is used, the following code will be written repeatedly

In fact, the only thing that may change with business usage is the call of the ajax interface

We reuse the rest and extract it into reusable logic

Core code:

(1) Encapsulate the general lazy loading data apisrc/utils/hooks.ts

// 自定义一些通用的compositions api
import {
    
     useIntersectionObserver } from '@vueuse/core'
import {
    
     ref } from 'vue'

// 封装通用的数据懒加载api
export function useLazyData(apiFn: () => void) {
    
    
  // 通过 ref 获得组件实例
  const target = ref(null)
  const {
    
     stop } = useIntersectionObserver(
    // target 是观察的目标dom容器,必须是dom容器,而且是vue3.0方式绑定的dom对象
    target,
    // isIntersecting 是否进入可视区域,true是进入 false是移出
    // observerElement 被观察的dom
    ([{
     
      isIntersecting }]) => {
    
    
      // 在此处可根据isIntersecting来判断,然后做业务
      if (isIntersecting) {
    
    
        stop()
        apiFn()
      }
    }
  )
  return target
}

(2) Optimize fresh products

<script lang="ts" setup>
const target = useLazyData(() => {
    
    
  home.getNewList()
})
</script>
<template>
  <div class="home-new">
    <HomePanel ref="target" title="新鲜好物" sub-title="新鲜出炉 品质靠谱">
    </HomePanel>
  </div>
</template>

(3) Optimize popularity recommendation

<script lang="ts" setup>
const target = useLazyData(() => {
    
    
  home.getHotList()
})
</script>
<template>
  <HomePanel ref="target" title="人气推荐" sub-title="人气爆款 不容错过">
  </HomePanel>
</template>

Expand small knowledge: custom lazyhook type optimization

export function useLazyApi(apiFn: () => void) {
    
    
  const target = ref<MaybeElementRef | null>(null)
  const {
    
    stop} = useIntersectionObserver(target, ([{
    
    isIntersecting}]) => {
    
    
    if (isIntersecting) {
    
    
      stop()
      apiFn()
    }
  })
  return target
}

Added ref type hint: MaybeElementRef -> exposed taget will prompt if the assignment type is wrong

insert image description here

Take a look at what type MaybeElementRef is?

declare type MaybeElementRef<T extends MaybeElement = MaybeElement> = MaybeRef<T>;
declare type MaybeElement = HTMLElement | SVGElement | VueInstance | undefined | null;
declare type MaybeRef<T> = T | Ref<T>;

To summarize: The types of the MaybeElementRef type are:

  • Ref type of MaybeElement
  • Or directly for the MayBeElement type

Home page main body - scroll loading product bug

  • The product area needs to scroll more to load the data.
  • threshold The ratio of the intersection of the container and the visible area (entered area/complete area of ​​the container) Value, between 0-1, the default is greater than 0, so more scrolling is required to trigger the event of entering the visible area. Threshold (area entered/full area of ​​container)
const {
    
     stop } = useIntersectionObserver(
  target,
  ([{
     
      isIntersecting }], observerElement) => {
    
    
    if (isIntersecting) {
    
    
      stop()
      // 调用API获取数据
      apiFn().then(data => {
    
    
        result.value = data.result
      })
    }
  },
  {
    
    
    threshold: 0
  }
)
rElement) => {
    
    
    if (isIntersecting) {
    
    
      stop()
      // 调用API获取数据
      apiFn().then(data => {
    
    
        result.value = data.result
      })
    }
  },
  {
    
    
    threshold: 0
  }
)

Guess you like

Origin blog.csdn.net/weixin_46862327/article/details/129114478