React无限滚动加载列表组件的封装实现
前言
由于需要考虑后端接口的性能问题,我们在请求业务数据列表的时候并不能直接请求全量数据。所以我们在请求数据时常见的方式是做分页查询。
对于前端交互而言,我们需要考虑如何优雅的让用户触发请求下一页数据的接口。常用的方法有两种:
- 提供显示的分页器,让用户自己手动点击下一页;
- 业务滚动到某个阈值时自动触发下一页请求;
对于移动端,滚动加载的交互是更加优雅的处理方式。对于滚动加载的能力,我们需要一个公共的组件来实现代码的复用,避免每次都要为滚动加载的需求伤脑筋。
效果图
先看效果,增加信心


准备工作
滚动事件的参数中核心属性
| clientWidth | 可视区宽度 |
|---|---|
| clientHeight | 可视区高度 |
| offsetWidth | 可视区宽度 |
| offsetHeight | 可视区高度 |
| scrollWidth | 内容实际宽度 |
| scrollHeight | 内容实际高度 |
| scrollTop | 内容顶部距离可视区顶部距离 |
| scrollLeft | 内容左侧距离可视图左侧距离 |
比较直观的示意图

实现原理
滚动加载的目的是用户滚动页面到最底部时可以自动请求下一页的数据接口,所以问题重点是如何确认用户的页面滚动到了最底部。
列表触底的条件:可视区高度 + 滚动距离 ≥ 内容实际高度
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('列表触底,触发接口请求数据');
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版的无限滚动组件。
组件能力介绍
- 业务方管理数据源dataSource,便于个性化业务操作;
- 支持自定义数据加载中skeleton;
- 增加触发门槛,减少无效的数据请求;
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
//可视区高度
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无限滚动加载列表组件的封装实现的文章就介绍到这了,更多相关React无限滚动加载列表内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
Ant Design与Ant Design pro入门使用教程
Ant Design 是一个服务于企业级产品的设计体系,组件库是它的 React 实现,antd 被发布为一个 npm 包方便开发者安装并使用,这篇文章主要介绍了Ant Design与Ant Design pro入门,需要的朋友可以参考下2023-12-12
详解开发react应用最好用的脚手架 create-react-app
本篇文章主要介绍了详解开发react应用最好用的脚手架 create-react-app,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧2018-04-04
React使用setState更新数组的方法示例(追加新数据)
在 React 中,setState 是管理组件状态的核心方法之一,然而,当我们需要更新状态中的数组时,如何高效且安全地操作变得尤为关键,本文将详细解析以下代码的实现逻辑,帮助你掌握在 React 中追加数组数据的最佳实践,需要的朋友可以参考下2025-03-03
React 中使用 Redux Toolkit 状态管理的实践
本文主要介绍了Redux的核心概念及Redux Toolkit的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧2025-09-09
React Native可复用 UI分离布局组件和状态组件技巧
这篇文章主要为大家介绍了React Native可复用 UI分离布局组件和状态组件使用技巧,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪2022-09-09


最新评论