3

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!

tao
  • 82,996
  • 16
  • 114
  • 150

1 Answers1

3
  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.

tao
  • 82,996
  • 16
  • 114
  • 150
  • Thank you for your kind, detailed, helpful response. I have tried using useInfiniteScroll on onMounted but it did not trigger the function, do you have more ideas about this issue? – eşelk eşekll May 31 '23 at 12:47
  • @eşelkeşekll, you're likely seeing some warnings/errors which are not present in your question. What you posted so far cannot be used to create a *runnable* [mcve]. Post your code on codesandbox.io and I'll have a closer look. – tao May 31 '23 at 12:49
  • The project i am working on is very big and detailed, i have checked my console for errors, and encountered anything – eşelk eşekll May 31 '23 at 12:52
  • Apart from being incomplete (missing imports and/or variable declarations) and the problems I stated in my answer, I can't spot anything else wrong in the code you posted. In general, nobody can help fix code without being able to see and/or run it. – tao May 31 '23 at 13:07
  • @eşelkeşekll, you don't have to provide your entire project. But you have to provide the minimal for anyone to repro. I have no way of knowing what versions you're using, if you [installed the plugin properly](https://github.com/Akryum/vue-virtual-scroller/blob/master/packages/vue-virtual-scroller/README.md), etc... Make sure you read and apply the *"Installation"* and *"Usage"* sections in the docs linked above. I won't be able to help further without a runnable example. – tao May 31 '23 at 13:12
  • 1
    you are right, I am sorry for missing information. After inspecting the issue further, i realized i am giving the ref value to an unscrollable element. Using infinite scroll on mounted hook solved the issue. Thanks for your help! – eşelk eşekll May 31 '23 at 13:32