Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can i use vue-virtual-scroller with vue use useInfiniteScroll?

I'm currently working on implementing infinite scroll in a Vue application using the useInfiniteScroll function from @vueuse/core. However, I'm facing an issue with binding the ref to the scrollable element.

The infinite scroll functionality is not working as expected. The useInfiniteScroll callback function is not triggered when scrolling near the bottom of the element. I am using vue-virtual-scroller for virtual list.

I have followed the steps mentioned in the documentation and made sure that:

  • The ref is correctly defined using the ref() function in my JavaScript code.

  • The ref is assigned to the scrollable element within the DynamicScroller.e-solution-list__body component, which I'm using in my template.

Here's my code:

<template lang="pug">
DynamicScroller.e-solution-list__body(:items="items" :min-item-size="54" v-if="items.length && !solutionTable.loading" :emit-update="true" ref="scroller")
        template(#default="{ item, index, active }")
          DynamicScrollerItem(:item="item" :active="active" :data-index="index")
            .e-solution-list__row(:key="item.id" :class="{ 'e-solution-list__row--expanded': isExpanded(item.id), 'e-solution-list__row--mobile-border': !isExpanded(item.id) || !item.tags.length }")
</template>
<script lang="ts">
import { useInfiniteScroll } from '@vueuse/core'
 setup(props) {
    const columns = ref(SOLUTION_COLUMNS)
    const id = ref(props.problemId)
    const solutionTable = reactive({
      loading: false,
      loadMore: false,
      data: [],
      totalCount: 0,
      query: {
        sortBy: '-createdDate',
        skip: 0,
        limit: USE_CASE_LIMIT,
        text: '',
        popPaths: 'solutionProviderList,actors,sfCategories,sfSubCategories,sfIndustries,sfTechnologies,sfTags'
      }
    })
    const scroller = ref<HTMLElement>(null)
 //infinite scroll
    nextTick(() => {
      useInfiniteScroll(
        scroller,
        () => {
          getRelatedSolutions({
            skip: items.value.length,
            limit: USE_CASE_LIMIT,
            loadMore: true,
            isScrollTop: false,
            sortBy: sortBy.isAscending ? sortBy.key : `-${sortBy.key}`
          })
        },
        {
          distance: ITEM_HEIGHT * 2
        }
      )
    })

    
}


</script>

Despite following these steps, the infinite scroll functionality is not working as expected. The `useInfiniteScroll` callback function is not triggered when scrolling near the bottom of the element. I have tried the following approaches, but none of them resolved the issue:

  1. Ensuring the `ref` is properly assigned within the `DynamicScroller.e-solution-list__body` component.

  2. Accessing the scrollable element using `document.getElementById()` or `document.querySelector()` instead of a `ref`.

  3. Wrapping the `useInfiniteScroll` call in the `$nextTick` function to ensure the DOM is updated.

I would appreciate any insights or suggestions on how to troubleshoot this issue and get the infinite scroll working correctly. Thank you!

like image 618
eşelk eşekll Avatar asked Oct 16 '25 02:10

eşelk eşekll


1 Answers

  1. The ref's value is null before the component is mounted. You have to defer initiating the infinite scroller to onMounted:
import { ref, onMounted, defineComponent } from 'vue'

export default defineComponent({
  //...
  setup(props) {
    // ...
    const scroller = ref<HTMLElement>(null)
    onMounted(() => {
      useInfiniteScroll(
        scroller,
        () => {
          getRelatedSolutions({
            //...
          })
        }
      )
    })
    return { 
      //...
      scroller // 👈 this is important if not using `<script setup>`
    }
  }
})
  1. If you're not using <script setup>, your setup function has to return all reactive references used by <template> (as shown above).

Important note: I noticed your <script> is not a <script setup> 1 and does not have a default export. If this is due to partial copy/pasting, ignore this note. But if that's what you're using, you should either:

  • wrap setup function in export default { /* code here */ }
  • wrap setup function in export default defineComponent({ /* code here */ }) (recommended, for typescript).

1 - <script setup> doesn't need a default export, as it takes the contents and treats it as if it was the contents of a setup() function, providing the necessary boilerplate for it in the compiled code.

like image 108
tao Avatar answered Oct 17 '25 16:10

tao



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!