DEV Community

Cover image for Lazy Loading with the IntersectionObserver API
Itachi Uchiha
Itachi Uchiha

Posted on

Lazy Loading with the IntersectionObserver API

Hi. In this post, I'll give some information about IntersectionObserver API.

Before we start, I should say this IE11 doesn't support this API. You can check which browsers support on the CanIUse.

Why?

There are many libraries that helping lazy loading operations. I know, but this API native. You may don't want to use external libraries etc.

In a project, we had many images and many list items. Because of that images, the page was loading in 10-15 seconds. This was terrible for us and our customers, visitors etc.

We found some solutions like server-side pagination. But this wasn't a good solution for our project. Because customers didn't want to reload the page.

In order to solve the problem, we found Verlok's lazyload library. But we also found IntersectionObserver API. Anyway, we decided to use IntersectionObserver API. We're using IntersectionObserver today. Okay, I'll show how.

HTML && CSS Codes

In this example, we'll use the Bootstrap 4's Card component. We also use the button component for tracking the index. Default index will be 0(zero).

<div class="container">
    <div class="row">
        <div class="col-md-12 card-container">

        </div>
    </div>
    <div class="row">
        <div class="col-md-12 load-more-container">
            <button data-index="0" class="btn btn-primary btn-block load-more">Load More</button>
        </div>
    </div>
</div>
Enter fullscreen mode Exit fullscreen mode

And the CSS will be like this. Just a little bit margin. Our cards look more pretty now.

.load-more-container {
    margin-top: 15px;
}

.card {
    margin-bottom: 15px;
}
Enter fullscreen mode Exit fullscreen mode

JavaScript Codes

I'll create a class. You may want to create a function. This depends on you. The class will start like this. Its name will be LazyLoad.

class LazyLoad {
    constructor() {
    this.btn = document.querySelector(".load-more")
    this.cardContainer = document.querySelector('.card-container')
    this.BASE_URL = 'https://picsum.photos/list'
    }
}
Enter fullscreen mode Exit fullscreen mode

We will API server for the images.

In this example, we always call all the images from this server. Because I couldn't find any pagination.

Then, I'll create a function called load.

load() {
        fetch(this.BASE_URL)
        .then(resp => resp.json())
        .then(obj => {
            let start = (this.btn.dataset.index == 0) ? parseInt(this.btn.dataset.index) : parseInt(this.btn.dataset.index) + 1
            let end = start + 5
            let arr = obj.slice(start, end)
            if(arr.length > 0) {
                let cards = '';
                arr.forEach(f => {
                    cards += `
                        <div class="card">
                          <div class="card-body">
                            <h5 class="card-title">${f.author}</h5>
                            <img src="https://picsum.photos/458/354/?image=${f.id}" alt="">
                          </div>
                        </div>
                    `
                })

                this.cardContainer.insertAdjacentHTML('beforeend',cards)
                this.btn.dataset.index = end
            }
        })
    }
Enter fullscreen mode Exit fullscreen mode

With this function, we will create fetch requests. We will also create HTML content thanks to template literals to put them to .card-container.

And the last thing, we will create a function called init. The function will be like this;

    init() {
        const container = document.querySelector(".load-more-container")
        let observer = new IntersectionObserver(entries => {
            entries.forEach(entry => {
                const { isIntersecting } = entry

                if(isIntersecting) {
                    this.load()
                    //observer = observer.disconnect()
                }
            }, {
                root: container
            })
        })

        observer.observe(container)
    }
Enter fullscreen mode Exit fullscreen mode

In the above code, when the element intersecting with the user' viewport codes will be run. IntersectionObserver gives two arguments. The first argument will be a callback. The second argument will be options. In this example, we have only root options.

The callback that receives one or more intersection entries. And observer will be observing the container we created.

observer.observe(container)
Enter fullscreen mode Exit fullscreen mode

Using observer = observer.disconnect() you will stop observing operations. Which means, more load functionality will not work.

Before Finishing

If you want to a real example, I've created an example on the CodePen. You can check it how it works.

Resources

MDN

David Walsh

I hope this post will help you with your projects.

Thanks for reading!

Top comments (5)

Collapse
 
rhymes profile image
rhymes • Edited

Very simple and effective, thanks!

Collapse
 
itachiuchiha profile image
Itachi Uchiha

You're welcome :)

Collapse
 
hrn4n profile image
Hernán

Very interesting, I love how there's always new web APIs to learn about!

Collapse
 
mattbag00 profile image
Matt Bagni

I started doing this recently, a great and simple native api. I also use it for other lazy parts such as iframes or Instagram feeds

Collapse
 
petecapecod profile image
Peter Cruckshank

Great examples! Can't wait to use this myself