Skip to content

⬅️ Back to Table of Contents

πŸ“„ useInfiniteScroll

πŸ“Š Analysis Summary

Metric Count
πŸ”§ Functions 2
πŸ“¦ Imports 16
⚑ Async/Await Patterns 2
🟒 Vue Composition API 5
πŸ“ Interfaces 2
πŸ“‘ Type Aliases 1

πŸ“š Table of Contents

πŸ› οΈ File Location:

πŸ“‚ packages/core/useInfiniteScroll/index.ts

πŸ“¦ Imports

Name Source
Awaitable @vueuse/shared
ComputedRef vue
MaybeRefOrGetter vue
UnwrapNestedRefs vue
UseScrollOptions ../useScroll
UseScrollReturn ../useScroll
tryOnUnmounted @vueuse/shared
computed vue
nextTick vue
reactive vue
shallowRef vue
toValue vue
watch vue
resolveElement ../_resolve-element
useElementVisibility ../useElementVisibility
useScroll ../useScroll

Async/Await Patterns

Type Function Await Expressions Promise Chains
promise-chain useInfiniteScroll none Promise.all([ onLoadMore(state), new Promise(resolve => setTimeout(resolve, i...
promise-chain checkAndLoad none Promise.all([ onLoadMore(state), new Promise(resolve => setTimeout(resolve, i...

Vue Composition API

Name Type Reactive Variables Composables
reactive reactive none none
computed computed none none
computed computed none none
computed computed none none
watch watch none none

Functions

useInfiniteScroll(element: MaybeRefOrGetter<T>, onLoadMore: (state: UnwrapNestedRefs<UseScrollRetur…, options: UseInfiniteScrollOptions<T>): UseInfiniteScrollReturn

Reactive infinite scroll.

See: https://vueuse.org/useInfiniteScroll

Raw JSDoc
/**
 * Reactive infinite scroll.
 *
 * @see https://vueuse.org/useInfiniteScroll
 */

Calls:

  • reactive (from vue)
  • useScroll (from ../useScroll)
  • shallowRef (from vue)
  • computed (from vue)
  • resolveElement (from ../_resolve-element)
  • toValue (from vue)
  • useElementVisibility (from ../useElementVisibility)
  • canLoadMore
  • state.measure
  • Promise.all([ onLoadMore(state), new Promise(resolve => setTimeout(resolve, interval)), ]) .finally
  • nextTick (from vue)
  • checkAndLoad
  • watch (from vue)
  • tryOnUnmounted (from @vueuse/shared)

Internal Comments:

// Document and Window cannot be observed by IntersectionObserver (x2)

Code
export function useInfiniteScroll<T extends InfiniteScrollElement>(
  element: MaybeRefOrGetter<T>,
  onLoadMore: (state: UnwrapNestedRefs<UseScrollReturn>) => Awaitable<void>,
  options: UseInfiniteScrollOptions<T> = {},
): UseInfiniteScrollReturn {
  const {
    direction = 'bottom',
    interval = 100,
    canLoadMore = () => true,
  } = options

  const state = reactive(useScroll(
    element,
    {
      ...options,
      offset: {
        [direction]: options.distance ?? 0,
        ...options.offset,
      },
    },
  ))

  const promise = shallowRef<Promise<unknown> | null>()
  const isLoading = computed(() => !!promise.value)

  // Document and Window cannot be observed by IntersectionObserver
  const observedElement = computed<HTMLElement | SVGElement | null | undefined>(() => {
    return resolveElement(toValue(element))
  })

  const isElementVisible = useElementVisibility(observedElement)

  const canLoad = computed(() => {
    if (!observedElement.value)
      return false
    return canLoadMore(observedElement.value as T)
  })

  function checkAndLoad() {
    state.measure()

    if (!observedElement.value || !isElementVisible.value || !canLoad.value || promise.value)
      return

    const { scrollHeight, clientHeight, scrollWidth, clientWidth } = observedElement.value as HTMLElement
    const isNarrower = (direction === 'bottom' || direction === 'top')
      ? scrollHeight <= clientHeight
      : scrollWidth <= clientWidth

    if (state.arrivedState[direction] || isNarrower) {
      promise.value = Promise.all([
        onLoadMore(state),
        new Promise(resolve => setTimeout(resolve, interval)),
      ])
        .finally(() => {
          promise.value = null
          nextTick(() => checkAndLoad())
        })
    }
  }

  const stop = watch(
    () => [state.arrivedState[direction], isElementVisible.value, canLoad.value],
    checkAndLoad,
    { immediate: true, flush: 'post' },
  )

  tryOnUnmounted(stop)

  return {
    isLoading,
    reset() {
      nextTick(() => checkAndLoad())
    },
  }
}

Internal helpers

Declared inside another function in this file.

checkAndLoad(): void

Returns: void

Calls:

  • state.measure
  • Promise.all([ onLoadMore(state), new Promise(resolve => setTimeout(resolve, interval)), ]) .finally
  • nextTick (from vue)
  • checkAndLoad
Code
function checkAndLoad() {
    state.measure()

    if (!observedElement.value || !isElementVisible.value || !canLoad.value || promise.value)
      return

    const { scrollHeight, clientHeight, scrollWidth, clientWidth } = observedElement.value as HTMLElement
    const isNarrower = (direction === 'bottom' || direction === 'top')
      ? scrollHeight <= clientHeight
      : scrollWidth <= clientWidth

    if (state.arrivedState[direction] || isNarrower) {
      promise.value = Promise.all([
        onLoadMore(state),
        new Promise(resolve => setTimeout(resolve, interval)),
      ])
        .finally(() => {
          promise.value = null
          nextTick(() => checkAndLoad())
        })
    }
  }

Interfaces

UseInfiniteScrollOptions<T extends InfiniteScrollElement = InfiniteScrollElement>

Interface Code
export interface UseInfiniteScrollOptions<T extends InfiniteScrollElement = InfiniteScrollElement> extends UseScrollOptions {
  /**
   * The minimum distance between the bottom of the element and the bottom of the viewport
   *
   * @default 0
   */
  distance?: number

  /**
   * The direction in which to listen the scroll.
   *
   * @default 'bottom'
   */
  direction?: 'top' | 'bottom' | 'left' | 'right'

  /**
   * The interval time between two load more (to avoid too many invokes).
   *
   * @default 100
   */
  interval?: number

  /**
   * A function that determines whether more content can be loaded for a specific element.
   * Should return `true` if loading more content is allowed for the given element,
   * and `false` otherwise.
   */
  canLoadMore?: (el: T) => boolean
}

Properties

Name Type Optional Description
distance number βœ“ not shown
direction 'top' \| 'bottom' \| 'left' \| 'right' βœ“ not shown
interval number βœ“ not shown
canLoadMore (el: T) => boolean βœ“ not shown

UseInfiniteScrollReturn

Interface Code
export interface UseInfiniteScrollReturn {
  isLoading: ComputedRef<boolean>
  reset: () => void
}

Properties

Name Type Optional Description
isLoading ComputedRef<boolean> βœ— not shown
reset () => void βœ— not shown

Type Aliases

InfiniteScrollElement

type InfiniteScrollElement = HTMLElement | SVGElement | Window | Document | null | undefined;

Generated by Syntax Scribe