還 ⭐ 的基於 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])])
}
複製代碼
看到這裏的小夥伴,有沒有以爲實現個長列表其實也很簡單呢~
文中的解析再對照着項目中的代碼看,相信你必定有所收穫
還有~~~別忘了👍~⭐~👍~⭐~👍~⭐~👍~⭐~👍~⭐~👍~⭐~👍~⭐~👍~⭐~👍~⭐~
複製代碼