前端 React實現(xiàn)數(shù)據(jù)懶加載和滾動觸底加載數(shù)據(jù)的過程
什么是React的懶加載(Lazy Loading),如何實現(xiàn)?
在現(xiàn)代前端開發(fā)中,性能是一個至關(guān)重要的指標。隨著應(yīng)用程序日益增長和復(fù)雜,如何有效地管理資源和優(yōu)化加載時間成為了每位開發(fā)者必須面對的挑戰(zhàn)。為此,React 提供了懶加載(Lazy Loading)這一強大功能,幫助開發(fā)者按需加載組件,提高應(yīng)用架構(gòu)的靈活性和性能。
懶加載的概念
懶加載是一種設(shè)計模式,只有在需要的時候才加載某個資源或組件,而不是在應(yīng)用啟動時一次性加載所有資源。在 React 中,懶加載通常用于組件的按需加載。通過懶加載,用戶可以避免在早期階段加載不必要的組件,實現(xiàn)流暢的用戶體驗,同時減少初始下載的大小。
為什么要使用懶加載
- 提升性能:通過只加載用戶需要的部分,減少了初始加載時間和數(shù)據(jù)傳輸?shù)拇笮?,從而提升?yīng)用的性能。
- 優(yōu)化用戶體驗:提高頁面響應(yīng)速度,使用戶能更快地查看和使用應(yīng)用的核心功能。
- 代碼分割:懶加載有助于實現(xiàn)代碼分割,將大文件拆分成多個小塊,用戶只有在交互需要時才會請求相應(yīng)的代碼。
在 React 中使用 Intersection Observer API 實現(xiàn)觸底加載分頁(無限滾動)
1.基本實現(xiàn)思路
- 在列表底部放置一個 哨兵元素(Sentinel)(如
<div>)。 - 使用
IntersectionObserver監(jiān)聽該元素是否進入視口(即觸底)。 - 觸底時加載下一頁數(shù)據(jù),并更新列表。
2.完整代碼實例
import { useState, useEffect, useRef } from 'react';
function InfiniteScrollList() {
const [data, setData] = useState([]); // 當前數(shù)據(jù)
const [page, setPage] = useState(1); // 當前頁碼
const [loading, setLoading] = useState(false); // 加載狀態(tài)
const [hasMore, setHasMore] = useState(true); // 是否還有更多數(shù)據(jù)
const sentinelRef = useRef(null); // 哨兵元素的 ref
// 模擬異步加載數(shù)據(jù)
const fetchData = async () => {
if (loading || !hasMore) return;
setLoading(true);
// 模擬 API 請求(替換為實際接口)
const mockData = Array.from({ length: 10 }, (_, i) =>
`Item ${(page - 1) * 10 + i + 1}`
);
// 模擬延遲
await new Promise(resolve => setTimeout(resolve, 1000));
setData(prev => [...prev, ...mockData]);
setPage(prev => prev + 1);
setLoading(false);
// 假設(shè)第 5 頁后無數(shù)據(jù)
if (page >= 5) setHasMore(false);
};
// 初始化 IntersectionObserver
useEffect(() => {
if (!sentinelRef.current || !hasMore) return;
const observer = new IntersectionObserver(
(entries) => {
const [entry] = entries;
if (entry.isIntersecting) {
fetchData(); // 觸底時加載數(shù)據(jù)
}
},
{ threshold: 1.0 } // 當哨兵元素完全進入視口時觸發(fā)
);
observer.observe(sentinelRef.current);
return () => {
if (sentinelRef.current) observer.unobserve(sentinelRef.current);
};
}, [page, hasMore, loading]); // 依賴項
return (
<div style={{ maxHeight: '400px', overflow: 'auto' }}>
<h2>無限滾動列表</h2>
<ul>
{data.map((item, index) => (
<li key={index} style={{ padding: '10px', borderBottom: '1px solid #eee' }}>
{item}
</li>
))}
</ul>
{/* 哨兵元素:用于檢測觸底 */}
<div ref={sentinelRef} style={{ height: '20px' }}>
{loading && <p>加載中...</p>}
{!hasMore && <p>沒有更多數(shù)據(jù)了</p>}
</div>
</div>
);
}
export default InfiniteScrollList;3.關(guān)鍵點說明
- 哨兵元素(Sentinel)
- 一個隱藏的
<div>作為觸底標記,通過ref綁定到IntersectionObserver。
- 一個隱藏的
- IntersectionObserver 配置
threshold: 1.0:當哨兵元素100%進入視口時觸發(fā)回調(diào)。- 在
useEffect中初始化并清理觀察器,避免內(nèi)存泄漏。
- 加載控制邏輯
loading防止重復(fù)請求。hasMore標記數(shù)據(jù)是否全部加載完畢。
- 性能優(yōu)化
- 使用
useCallback包裹 fetchData(如果函數(shù)邏輯復(fù)雜)。 - 實際項目中,結(jié)合分頁接口的
total字段判斷是否還有數(shù)據(jù)。
- 使用
4.實際項目適配
- 替換 fetchData 中的模擬請求為真實 API 調(diào)用(如 axios 或 fetch)。
- 可加入防抖(Debounce)優(yōu)化頻繁觸發(fā)問題(如快速滾動時)。
簡易封裝觸底自動加載數(shù)據(jù)組件 InfiniteScroll.jsx
import { useEffect, useRef } from 'react'
const InfiniteScroll = (props) => {
// children 可以設(shè)置觸底時顯示的提示文字,加載狀態(tài)等
// loadMore 加載數(shù)據(jù)的接口方法
// hasMore 檢查數(shù)據(jù)是否全部加載完畢,分頁加載之后還有下一頁數(shù)據(jù)保持 true 不變,確保后續(xù)不會再有數(shù)據(jù)則為 false
// rootElement 瀏覽器可視窗口或者自定義滾動視口
const { children, loadMore, hasMore, rootElement = null } = props
const sentinelRef = useRef(null)
useEffect(() => {
if (!sentinelRef.current || !hasMore) return;
const observer = new window.IntersectionObserver(
([{isIntersecting}]) => {
if (isIntersecting) {
// 加載數(shù)據(jù)接口調(diào)用,當該組件進入瀏覽器視口時就會觸發(fā)
loadMore()
}
},
{ threshold: 1.0, root: rootElement }
);
observer.observe(sentinelRef.current);
return () => {
if (sentinelRef.current) observer.unobserve(sentinelRef.current);
};
}, [hasMore])
return (
// 哨兵容器,目標元素,用來監(jiān)聽是否加載數(shù)據(jù),目標元素與視口交叉 isIntersecting 值就會變化
<div ref={sentinelRef} style={{ minHeight: '2px', textAlign: 'center' }}>
{children}
</div>
)
}
export default InfiniteScroll使用示例
const CustomComponent = () => {
// 加載數(shù)據(jù)函數(shù)
const loadMore = () => {
// ...
}
return (
<>
// ...
// 循環(huán)數(shù)據(jù),將組件放置在循環(huán)數(shù)據(jù)的底部即可
<InfiniteScroll loadMore={loadMore} hasMore={hasMore}>
{hasMore && <Spin indicator={<LoadingOutlined spin />} size="large" />}
</InfiniteScroll>
// ...
</>
)
}到此這篇關(guān)于前端 React實現(xiàn)數(shù)據(jù)懶加載和滾動觸底加載數(shù)據(jù)的過程的文章就介紹到這了,更多相關(guān)React懶加載和滾動觸底加載內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
react-native 實現(xiàn)購物車滑動刪除效果的示例代碼
這篇文章主要介紹了react-native 實現(xiàn)購物車滑動刪除效果的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01
jsoneditor二次封裝實時預(yù)覽json編輯器組件react版
這篇文章主要為大家介紹了jsoneditor二次封裝實時預(yù)覽json編輯器組件react版示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-10-10
React實現(xiàn)模糊搜索和關(guān)鍵字高亮的示例代碼
這篇文章主要為大家詳細介紹了React如何實現(xiàn)模糊搜索和關(guān)鍵字高亮的效果,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-11-11
React使用高德地圖的實現(xiàn)示例(react-amap)
這篇文章主要介紹了React使用高德地圖的實現(xiàn)示例(react-amap),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04

