React無限滾動加載列表組件的封裝實現(xiàn)
前言
由于需要考慮后端接口的性能問題,我們在請求業(yè)務數(shù)據(jù)列表的時候并不能直接請求全量數(shù)據(jù)。所以我們在請求數(shù)據(jù)時常見的方式是做分頁查詢。
對于前端交互而言,我們需要考慮如何優(yōu)雅的讓用戶觸發(fā)請求下一頁數(shù)據(jù)的接口。常用的方法有兩種:
- 提供顯示的分頁器,讓用戶自己手動點擊下一頁;
- 業(yè)務滾動到某個閾值時自動觸發(fā)下一頁請求;
對于移動端,滾動加載的交互是更加優(yōu)雅的處理方式。對于滾動加載的能力,我們需要一個公共的組件來實現(xiàn)代碼的復用,避免每次都要為滾動加載的需求傷腦筋。
效果圖
先看效果,增加信心


準備工作
滾動事件的參數(shù)中核心屬性
| clientWidth | 可視區(qū)寬度 |
|---|---|
| clientHeight | 可視區(qū)高度 |
| offsetWidth | 可視區(qū)寬度 |
| offsetHeight | 可視區(qū)高度 |
| scrollWidth | 內容實際寬度 |
| scrollHeight | 內容實際高度 |
| scrollTop | 內容頂部距離可視區(qū)頂部距離 |
| scrollLeft | 內容左側距離可視圖左側距離 |
比較直觀的示意圖

實現(xiàn)原理
滾動加載的目的是用戶滾動頁面到最底部時可以自動請求下一頁的數(shù)據(jù)接口,所以問題重點是如何確認用戶的頁面滾動到了最底部。
列表觸底的條件:可視區(qū)高度 + 滾動距離 ≥ 內容實際高度
offsetHeight + scrollTop ≥ scrollHeight
核心代碼
scrollEvent = async (e) => {
let scrollHeight = e.target.scrollHeight;
let scrollTop = e.target.scrollTop;
let offsetHeight = e.target.offsetHeight;
if (offsetHeight + scrollTop >= scrollHeight) {
console.log('列表觸底,觸發(fā)接口請求數(shù)據(jù)');
this.setState({ loading: true });
let result = await this.loadData();
this.setState({
loading: false,
list: this.state.list.concat(result),
});
}
};
window.addListener('scroll',()=>scrollEvent())
組件封裝
為了讓代碼能夠更高的得到復用,將代碼封裝成UI組件是必要的,于是我封裝了一個簡易的React版的無限滾動組件。
組件能力介紹
- 業(yè)務方管理數(shù)據(jù)源dataSource,便于個性化業(yè)務操作;
- 支持自定義數(shù)據(jù)加載中skeleton;
- 增加觸發(fā)門檻,減少無效的數(shù)據(jù)請求;
import React, { ReactNode, useEffect, useRef } from 'react'
import classnames from 'classnames'
interface InfiniteScrollListProps<T> {
loading: boolean
dataSource: Array<T>
renderItem: (data: T) => ReactNode
renderSkeleton?: () => ReactNode
hasMore: boolean
loadMore: () => void
className?: string
}
export default function InfiniteScrollList<T>(props: InfiniteScrollListProps<T>) {
const { loading, dataSource, renderItem, renderSkeleton, loadMore, hasMore, className } = props
const containerRef = useRef<HTMLDivElement>(null)
useEffect(() => {
const scrollEvent = (event) => {
if (!hasMore || loading) return
//可視區(qū)高度
let scrollHeight = event.target?.scrollHeight
//滾動高度
let scrollTop = event.target.scrollTop
//列表內容實際高度
let offsetHeight = event.target.offsetHeight
if (offsetHeight + scrollTop >= scrollHeight) {
console.log('列表觸底')
loadMore()
}
}
containerRef.current?.addEventListener('scroll', scrollEvent)
return () => {
containerRef.current?.removeEventListener('scroll', scrollEvent)
}
}, [hasMore, loading])
return (
<div className={classnames('flex-1 flex flex-col overflow-y-auto', className)} ref={containerRef}>
{dataSource.map((data) => {
return renderItem(data)
})}
{loading && new Array(4).fill(0).map(() => renderSkeleton?.())}
</div>
)
}到此這篇關于React無限滾動加載列表組件的封裝實現(xiàn)的文章就介紹到這了,更多相關React無限滾動加載列表內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
詳解如何在React中優(yōu)雅的使用addEventListener
這篇文章主要為大家詳細介紹了如何在React中優(yōu)雅的使用addEventListener,文中的示例代碼簡潔易懂,對大家學習React有一定的幫助,需要的可以參考一下2023-01-01
react性能優(yōu)化useMemo與useCallback使用對比詳解
這篇文章主要為大家介紹了react性能優(yōu)化useMemo與useCallback使用對比詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-08-08

