还 ⭐ 的基于 react-hooks 和 react-virtualized 写的虚拟滚动搭配上拉下滑加载的 scroll 组件
🌟🌟 github.com/DavidWong97… 🌟🌟
写出来的小玩意可能不是特别完美,若是能给大伙们提供到思路或者帮助,实在不胜荣幸
也但愿大伙们给个 star 啦~react
相信用过 antd-mobile 的小伙伴都知道里面的 ListView 组件
组件还算是能知足不少须要的
但遇到数据量大时可能就不太够用了
并且一些不熟悉 useMemo 的小伙伴对于 ListView 的优化可能会不知所措
因此我就封装了一个不须要本身优化 renderRow,又能作到虚拟滚动,又能知足 ListView 基本须要的组件
接下来就一步步拆解,如何实现这个组件😈
复制代码
1. 背景
当遇到数据量大的列表渲染,如10万条数据,一次性渲染十万个元素,内存消耗确定是裂开的
这时候考虑怎么展现完列表,又能优化性能提高体验 —— 虚拟滚动
2. 效果描述
建立一个容器,容器内部展现固定数量的数据,经过先后索引肯定渲染数据的哪一个区间
复制代码
1. 找出渲染区间
a. startIndex: Math.max(0, startIndex - threshold),
b. stopIndex: Math.min(rowCount - 1, stopIndex + threshold)
c. threshold为列表项目数,默认15
2. 触发渲染
_invokeRendered【渲染列表】
a. componentDidMount
b. componentDidUpdate
3. 对比后渲染
每次渲染会缓存上一次的属性,若属性【如index】不同,从新渲染
复制代码
1. 构成:refresh + virtualScroll + loadMore
2. 状态控制 STATS
a. init - 初始状态
b. dragging - 拖动中
c. pre-refresh - 拖动达到最大限制,刷新状态就绪
d. not-enough - 拖动未达到最大限制
e. refreshing - 松手,正在刷新
f. success - 刷新成功
3. refresh 实现
a. onTouchStart
记录startY,若状态为refreshing或success,不执行
若scrollTop不为0,不执行
b. onTouchMove
计算logo的offset -> 当前pageY - startY
根据条件设置offset
① 0 < offset && offset <= 下拉最大限制,设为计算得出的offset
② offset < 0,设为0
③ offset > 下拉最大限制,设为下拉最大限制
若 offset >= 下拉最大限制,状态设为pre-refresh
不然若 offset < 下拉最大限制,状态设为dragging
c. onTouchEnd
若STATS为 pre-refresh
有传入回调onPullDown则调用,状态变动为 refreshing
回调执行完,状态变动为 success,延迟后变为init
不然
状态变动为 not-enough,延迟后变为init
4. virtualScroll 实现
a. 渲染传入的自定义组件children
b. 若传入data有数据,渲染vList
5. loadMore 实现
vList 中的 rowRenderer
① 传入对应的参数给 row 组件并渲染
② 根据状态渲染loading和没有更多的展现
6. onScroll回调封装一层
a. 有传入onScroll,执行回调onScroll
b. 有传入onPullUp
若 clientHeight + scrollTop === scrollHeight
则到达底部,执行回调onPullUp
复制代码
useMemo
优化,列表数据其中一项只要更改,列表全部项都会从新渲染,形成性能浪费JSON.stringify
数据做判断const Row = ({ row, data, index, info }:any) => {
return useMemo(() => row({ data: data, index, info }), [JSON.stringify(data[index])])
}
复制代码
看到这里的小伙伴,有没有以为实现个长列表其实也很简单呢~
文中的解析再对照着项目中的代码看,相信你必定有所收获
还有~~~别忘了👍~⭐~👍~⭐~👍~⭐~👍~⭐~👍~⭐~👍~⭐~👍~⭐~👍~⭐~👍~⭐~
复制代码