# Build an exceptional Infinite Scroller using Intersection Observer in Vue3

Intersection Observer is an API in JavaScript that allows you to detect when an element enters or leaves a viewport. This can be useful for things like lazy loading images or triggering animations.

In this blog post, we will walk through the process of building a Vue 3 single-page component that wraps the [Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) and makes it easy to use in our Vue applications.

### 1\. Create the Component

First, we’ll create a new component called `InfiniteScrollWrapper.vue`. This component will be responsible for wrapping the Intersection Observer API and exposing it to other components in our application.

### 2\. Defining the template

Next, we will define the template for the component. It consists of a wrapper div `<div ref="wrapper"></div>` , a vue slot to include elements inside the wrapper `<slot/>` and an ending div`<div ref="end"></div>` . In this case, we'll be observing the`<div ref="end"></div>` element.

```javascript
<template>
    <div ref="wrapper" class="wrapper">
        <slot/>
        <div ref="end" class="scroll_end">
            <span>Load More</span>
        </div>
    </div>
</template>

<script>
import { ref } from "vue"

export default{
  name: 'InfiniteScrollWrapper',
  
  setup(props, {emits}) {
    const wrapper = ref(null)
    const end = ref(null)

    return {
        end,
        wrapper,
    }
  }
}
</script>
```

### 3\. Adding the observer

In the `setup()` function, we'll define a `onMounted()` lifecycle hook where we will register the observer.

Firstly we create a new IntersectionObserver and assign it to `observer` variable. The intersection observer takes a function that will take the entries from the observer and check if the entry is intersecting and a reference to the wrapper (root) element. If any entry is intersecting, it will emit an event `infinte`.

Finally, we’ll observe the element by passing the end element ref to the observer’s `observe` method in the lifecycle hook.

```javascript
<template>
    <div ref="wrapper" class="wrapper">
        <slot/>
        <div ref="end" class="scroll_end">
            <span>Load More</span>
        </div>
    </div>
</template>

<script>
import { onMounted, ref } from "vue"

export default{
  name: 'InfiniteScrollWrapper',
  
  setup(props, {emits}) {
    const wrapper = ref(null)
    const end = ref(null)

    onMounted(() => {
        const observer = new IntersectionObserver((entries) => {
            entries.forEach(entry => {
                if (entry.isIntersecting) {
                    emit("infinite")
                }
            })
        }, { root: wrapper.value})

        observer.observe(end.value)
    })

    return {
        end,
        wrapper,
    }
  }
}
</script>
```

### 4\. Using it in a component

Now, we will create a `ProductsList` component which displays 3 products on intital load and when we scroll adds 3 more components to the view. We will use the `InfiniteScrollWrapper` component we created above to find when the elements intersect and load more products.

```javascript
<template>
    <div class="container">
        <InfiniteScrollWrapper class="products_list" :show-more="hasMoreItems" @infinite="loadMore">
            <div v-for="(product, index) in products"
                 :key="index"
                 class="product">
                {{ product }}
            </div>
        </InfiniteScrollWrapper>
    </div>
</template>

<script>
    import { ref } from "vue"
    import InfiniteScrollWrapper from "../Components/InfiniteScrollWrapper.vue"
    export default {
        name: "ProductsList",

        components: {
            InfiniteScrollWrapper,
        },
       
        setup() {
            const products = ref(["Magazines", "Toothpaste", "Food"])
            const hasMoreItems = ref(true)
            const loadMore = () => {
                if (!hasMoreItems.value) {
                    return
                }

                products.value = [...products.value, "Candy", "Detergent", "Shampoo"]
                hasMoreItems.value = false
            }

            return {
                hasMoreItems,
                products,
                loadMore,
            }
        },
    }
</script>
```

%[https://vimeo.com/792854421] 

This is what the actual implementation of the component looks like.

### 5\. Threshold

The `threshold` accepts a value between 0 and 1 and represents the percentage of the elements that must be visible before `isIntersecting` becomes true. By default this is set to 0 which means as soon as any part of the element is visible it will be considered intersecting. We can however take it as a prop to the current `InfiniteScrollWrapper` component.

```javascript
<template>
    <div ref="wrapper" class="wrapper">
        <slot/>
        <div ref="end" class="scroll_end">
            <span>Load More</span>
        </div>
    </div>
</template>

<script>
export default{
  name: 'InfiniteScrollWrapper',

  props: {
      threshold: { type: Number, default: 0 },
  },

  setup(props, {emits}) {
      const wrapper = ref(null)
      const end = ref(null)
  
      onMounted(() => {
          const observer = new IntersectionObserver((entries) => {
              entries.forEach(entry => {
                  if (entry.isIntersecting) {
                      emit("infinite")
                  }
              })
          }, { root: wrapper.value, threshold: props.threshold })
  
          observer.observe(end.value)
      })
  
      return {
          end,
          wrapper,
      }
  }
}
</script>
```

%[https://vimeo.com/792855309] 

### Get the Code

You can find the final code for this project in a [**GitHub repository.**](https://github.com/saninmersion/vue-infinite-scroller)

### Conclusion

In conclusion, the Intersection Observer API allows for efficient monitoring of elements within the viewport and can help improve the performance and user experience of a web page. This article provides a step-by-step guide on how to use the Intersection Observer API in a Vue.js project, including how to set up the observer, track the intersection of elements, and load additional content as needed.

👏👏 So, I suggest you give your a try on your project and enjoy it!

Feel free to share your thoughts and opinions and leave me a comment if you have any problems or questions.
