Search⌘ K
AI Features

Custom LazyLoad Component

Explore how to build a Vue Custom LazyLoad component that leverages Intersection Observer and idle callbacks for efficient lazy loading. Learn to optimize your app by loading large components only when needed, reducing unnecessary rendering and improving performance.

We'll cover the following...

We’ve just covered how we can lazy load a component with an Intersection Observer. It’d be admittedly tedious to add the same logic everywhere we want to lazy load components, though, especially if there are a few of them.

Custom component

Let’s create a component that will make it easier to lazy load components when the browser is idle, or if a user scrolls close to the component to render.

JavaScript (JSX)
// LazyLoad.vue
<script>
import { ref, watch, onMounted } from 'vue'
import { useIntersectionObserver } from '@/composables'
const isClient = typeof window !== 'undefined'
const loadOnIntersect = ({ containerRef, loadComponent, observerOptions }) => {
const { isIntersecting } = useIntersectionObserver(
containerRef,
observerOptions
)
watch(isIntersecting, isIntersecting => {
isIntersecting && loadComponent()
})
}
const loadOnIdle = ({ loadComponent, idleTimeout }) => {
// Load component immediately if not in the browser environment
// or if one of the necessary APIs is not supported
if(!isClient || Dat!('requestIdleCallback' in window || !('requestAnimationFrame' in window)))
{
loadComponent()
return
}
// Load the component when the browser is free or schedule it
// after the timeout is reached
requestIdleCallback(
() => {
requestAnimationFrame(loadComponent)
},
{ timeout: idleTimeout }
)
}
export default {
props: {
idleTimeout: {
type: Number,
default: 3000,
},
onIdle: {
type: Boolean,
default: false,
},
onVisible: {
type: [Object, Boolean],
default: null,
},
},
setup(props, { slots, emit})
{
const isComponentLoaded = ref(false)
const containerRef = ref(null)
let loadType = 'onIdle'
if(props.onIdle) loadType = 'onIdle'
else if(props.onVisible) loadType = 'onVisible'
const config = {
onIdle: loadOnIdle,
onVisible: loadOnIntersect,
}
const loadComponent = () => {
isComponentLoaded.value = true
emit('loaded')
}
// Call appropriate handler
config[loadType]({
containerRef,
loadComponent,
idleTimeout: props.idleTimeout,
observerOptions: typeof props.onVisible === 'object' ? props.onVisible : {},
})
/**
* If component is to be loaded then pass through slots
* Otherwise, render a div with a ref that is needed for
* the Intersection Observer
*/
return() =>
isComponentLoaded.value ? slots.default() : < div ref = { containerRef }
/>
},
}
</script>

The LazyLoad component accepts the onVisible, onIdle, and idleTimeout props. The onVisible prop indicates if a component should be rendered using an Intersection Observer. It accepts a boolean or a config object for the Intersection Observer. Next, we have the onIdle prop. If it sets to true ...