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


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

實(shí)現(xiàn)原理
滾動(dòng)加載的目的是用戶滾動(dòng)頁(yè)面到最底部時(shí)可以自動(dòng)請(qǐng)求下一頁(yè)的數(shù)據(jù)接口,所以問(wèn)題重點(diǎn)是如何確認(rèn)用戶的頁(yè)面滾動(dòng)到了最底部。
列表觸底的條件:可視區(qū)高度 + 滾動(dòng)距離 ≥ 內(nèi)容實(shí)際高度
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ā)接口請(qǐng)求數(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())
組件封裝
為了讓代碼能夠更高的得到復(fù)用,將代碼封裝成UI組件是必要的,于是我封裝了一個(gè)簡(jiǎn)易的React版的無(wú)限滾動(dòng)組件。
組件能力介紹
- 業(yè)務(wù)方管理數(shù)據(jù)源dataSource,便于個(gè)性化業(yè)務(wù)操作;
- 支持自定義數(shù)據(jù)加載中skeleton;
- 增加觸發(fā)門(mén)檻,減少無(wú)效的數(shù)據(jù)請(qǐng)求;
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
//滾動(dòng)高度
let scrollTop = event.target.scrollTop
//列表內(nèi)容實(shí)際高度
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>
)
}到此這篇關(guān)于React無(wú)限滾動(dòng)加載列表組件的封裝實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)React無(wú)限滾動(dòng)加載列表內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
React 組件轉(zhuǎn) Vue 組件的命令寫(xiě)法
本文先介紹兩個(gè)框架的組件共性和不兼容的地方,再介紹react-to-vue的使用和原理,需要的朋友可以參考下2018-02-02
React項(xiàng)目配置prettier和eslint的方法
這篇文章主要介紹了React項(xiàng)目配置prettier和eslint的相關(guān)知識(shí),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06
詳解如何在項(xiàng)目中使用jest測(cè)試react native組件
本篇文章主要介紹了詳解如何在項(xiàng)目中使用jest測(cè)試react native組件,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-02-02
基于React.js實(shí)現(xiàn)原生js拖拽效果引發(fā)的思考
這篇文章主要為大家詳細(xì)介紹了基于React.js實(shí)現(xiàn)原生js拖拽效果,繼而引發(fā)的一系列思考,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-03-03
react中將html字符串渲染到頁(yè)面的實(shí)現(xiàn)方式
這篇文章主要介紹了react中將html字符串渲染到頁(yè)面的實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12
基于webpack開(kāi)發(fā)react-cli的詳細(xì)步驟
這篇文章主要介紹了基于webpack開(kāi)發(fā)react-cli的詳細(xì)步驟,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-06-06
React前端開(kāi)發(fā)createElement源碼解讀
這篇文章主要為大家介紹了React前端開(kāi)發(fā)createElement源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11
在console中打印React Fiber樹(shù)的操作步驟
React Fiber 是 React 16 中引入的新的協(xié)調(diào)引擎或重寫(xiě)的核心算法, 真針Fiber的一個(gè)重要的核心概念Fiber Node,這次主要的研究對(duì)象是: 如何從使用者/學(xué)習(xí) 者角度 在js 代碼上 拿到fiber 樹(shù)結(jié)構(gòu)的信息,,需要的朋友可以參考下2024-04-04
詳解react如何實(shí)現(xiàn)復(fù)合組件
在一些react項(xiàng)目開(kāi)發(fā)中,常常會(huì)出現(xiàn)一些組合的情況出現(xiàn),這篇文章主要為大家介紹了復(fù)合組件的具體實(shí)現(xiàn),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-10-10

