还 ⭐ 的基于 react-hooks 和 react-virtualized 写的虚拟滚动搭配上拉下滑加载的 scroll 组件
🌟🌟 github.com/DavidWong97… 🌟🌟
写出来的小玩意可能不是特别完美,如果能给大伙们提供到思路或者帮助,实在不胜荣幸
也希望大伙们给个 star 啦~
相信用过 antd-mobile 的小伙伴都知道里面的 ListView 组件 组件还算是能满足很多需要的 但遇到数据量大时可能就不太够用了 而且一些不熟悉 useMemo 的小伙伴对于 ListView 的优化可能会不知所措 所以我就封装了一个不需要自己优化 renderRow,又能做到虚拟滚动,又能满足 ListView 基本需要的组件 接下来就一步步拆解,如何实现这个组件😈 复制代码
1. 背景<br> 当遇到数据量大的列表渲染,如10万条数据,一次性渲染十万个元素,内存消耗肯定是裂开的<br> 这时候考虑怎么展示完列表,又能优化性能提升体验 —— 虚拟滚动 2. 效果描述<br> 创建一个容器,容器内部展示固定数量的数据,通过前后索引确定渲染数据的哪个区间 复制代码
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])]) } 复制代码
看到这里的小伙伴,有没有觉得实现个长列表其实也很简单呢~ 文中的解析再对照着项目中的代码看,相信你一定有所收获 还有~~~别忘了👍~⭐~👍~⭐~👍~⭐~👍~⭐~👍~⭐~👍~⭐~👍~⭐~👍~⭐~👍~⭐~ 复制代码