All files / react useReachBottom.ts

100% Statements 22/22
100% Branches 11/11
100% Functions 5/5
100% Lines 22/22

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69                                      6x   6x   6x 6x 10x               6x     6x 3x 3x     3x 3x 2x     3x 3x     3x 3x 2x           6x   6x 6x 6x       6x    
/**
 * Modified from https://github.com/karl-run/react-bottom-scroll-listener/blob/master/src/hook/index.tsx
 */
import { bindEvent, debounce } from '../utils'
import { MutableRefObject, useEffect, useRef } from 'react'
import { useLatest } from 'react-use'
 
/**
 * 立即触发一次回调,并且每当到达页面底部时触发回调。
 *
 * @public
 * @param callback 回调
 * @param offset 触底偏移量
 * @returns 返回
 */
export function useReachBottom<T extends HTMLElement>(
  callback: () => any,
  offset = 0,
): MutableRefObject<T> {
  const containerRef = useRef<T>(null)
 
  const latestCallback = useLatest(callback)
 
  useEffect(() => {
    const latestDebouncedCallback = debounce(
      () => latestCallback.current(),
      200,
      {
        leading: true,
        trailing: true,
      },
    )
 
    const unbindEvent = bindEvent(
      (containerRef.current as HTMLElement | null) || window,
    )('scroll', function () {
      if (this === window) {
        const scrollNode = document.scrollingElement || document.documentElement
        const scrollContainerBottomPosition = Math.round(
          scrollNode.scrollTop + window.innerHeight,
        )
        const scrollPosition = Math.round(scrollNode.scrollHeight - offset)
        if (scrollPosition <= scrollContainerBottomPosition) {
          latestDebouncedCallback()
        }
      } else {
        const scrollNode = containerRef.current!
        const scrollContainerBottomPosition = Math.round(
          scrollNode.scrollTop + scrollNode.clientHeight,
        )
        const scrollPosition = Math.round(scrollNode.scrollHeight - offset)
        if (scrollPosition <= scrollContainerBottomPosition) {
          latestDebouncedCallback()
        }
      }
    })
 
    // 立即触发一次回调
    latestDebouncedCallback()
 
    return () => {
      unbindEvent()
      latestDebouncedCallback.cancel()
    }
  }, [offset])
 
  return containerRef as any
}