Lazy load a video
Tags: webdev, javascript, react, typescript
Published: 2024-04-05 03:26:45

Lazy loading is an awesome technique that delays the loading of non-essential resources, such as images and videos, until they're actually needed. This can make a huge difference in how quickly a website loads, especially for pages with a lot of media content.

In one of our previous posts, we showed you how to lazy load images using the `IntersectionObserver` API. In this post, we'll take it a step further and show you how to use the same technique to lazy load videos too.

## Using IntersectionObserver to detect when a video is visible

The `IntersectionObserver` API is a powerful tool that lets you know when an element enters or leaves the viewport. This is particularly useful for lazy loading because we only want to load a video when the user can actually see it.

Here's the code snippet that shows how we can do it:

```jsx
const videoRef = React.useRef<HTMLVideoElement>(null);

React.useEffect(() => {
    const video = videoRef.current;
    if (!video) {
        return;
    }

    const observer = new IntersectionObserver((entries) => {
        entries.forEach((entry) => {
            if (entry.isIntersecting) {
                video.src = video.dataset.src;
                observer.unobserve(video);
            }
        });
    }, {
        threshold: 0,
    });

    observer.observe(video);

    return () => {
        observer.unobserve(video);
    };
}, []);

return (
    <video
        ref={videoRef}
        data-src="/path/to/video.mp4"
        controls
    />
);
```

In this example, we create a reference called `videoRef` and attach it to the `<video>` element. Then, we use a `useEffect` hook to create a new instance of `IntersectionObserver` that will watch the video element.

When the video becomes visible (i.e., it intersects with the viewport), the observer callback is triggered. Inside the callback, we set the `src` attribute of the video to the value of the `data-src` attribute, which contains the actual video URL.

To prevent the video from being loaded again if it leaves and re-enters the viewport, we unobserve the video element.

Check out the demo below to see it in action!

> Video credit: [City traffic](https://pixabay.com/videos/trafic-city-traffic-drone-53902/) by [@xat-ch](https://pixabay.com/users/xat-ch-12531001/)

{% codesandbox fjfghd %}

## Displaying a loading indicator

It's always a good idea to show a loading indicator while the video is loading. This lets the user know that something is happening. You can easily achieve this by conditionally rendering a loading spinner based on the video's loading state.

```tsx
const [isLoading, setIsLoading] = React.useState(true);

const handleLoadedData = () => {
    setIsLoading(false);
};

return (
    <div className="container">
        {isLoading && <div className="loading">Loading...</div>}
        <video
            ref={videoRef}
            data-src="/path/to/video.mp4"
            onLoadedData={handleLoadedData}
            controls
        />
    </div>
);
```

To improve the user experience, we can add a `isLoading` state variable that starts out as `true`. We also attach an `onLoadedData` event handler to the video that sets `isLoading` to `false` once the video metadata has loaded.

To visually indicate to the user that the video is loading, we conditionally render a loading indicator element in the JSX if `isLoading` is `true`. This loading indicator can be any kind of spinner or placeholder you want.

Check out the demo below. Scroll down to the bottom to see the loading indicator appear before the video is completely loaded.

{% stackblitz https://stackblitz.com/edit/lazy-load-a-video-2?file=src%2FApp.tsx&view=preview&embed=1 %}

## Conclusion

One way to improve your website's performance is by using `IntersectionObserver` to lazy load videos. This means that the videos won't load until the user can see them, which reduces page load time and saves bandwidth.

Don't forget to add a loading indicator when you implement lazy loading. This will let users know that content is coming and improve their experience on your website.

---

If you want more helpful content like this, feel free to follow me:

-   [DEV](https://dev.to/phuocng)
-   [GitHub](https://github.com/phuocng)
-   [Website](https://phuoc.ng)