欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

React無限滾動(dòng)插件react-infinite-scroll-component的配置優(yōu)化技巧

 更新時(shí)間:2025年09月16日 09:19:05   作者:沖浪的鵬多多  
react-infinite-scroll-component是React無限滾動(dòng)插件,簡(jiǎn)化滾動(dòng)加載邏輯,支持自定義提示和觸發(fā)距離,兼容移動(dòng)端,體積小巧,適用于列表、聊天等場(chǎng)景,需結(jié)合虛擬滾動(dòng)優(yōu)化性能,本文介紹React無限滾動(dòng)插件react-infinite-scroll-component的配置+優(yōu)化,感興趣的朋友一起看看吧

1. 前言

react-infinite-scroll-component 是 React 生態(tài)中一款輕量、易用的無限滾動(dòng)插件,核心目標(biāo)是幫助開發(fā)者快速實(shí)現(xiàn)“滾動(dòng)到底部自動(dòng)加載更多”的交互效果。它無需手動(dòng)監(jiān)聽滾動(dòng)事件、計(jì)算滾動(dòng)位置,而是通過封裝好的組件化 API,簡(jiǎn)化無限滾動(dòng)的實(shí)現(xiàn)邏輯,同時(shí)支持加載狀態(tài)顯示、無更多數(shù)據(jù)提示、自定義觸發(fā)距離等實(shí)用功能。

相比原生實(shí)現(xiàn)或其他同類插件,其核心優(yōu)勢(shì)如下:

  • 零冗余代碼:無需手動(dòng)處理 scroll 事件監(jiān)聽、滾動(dòng)高度計(jì)算等底層邏輯;
  • 高度可定制:支持自定義加載中組件、無更多數(shù)據(jù)提示、觸發(fā)加載的距離閾值;
  • 兼容性強(qiáng):適配 PC 端與移動(dòng)端,支持滾動(dòng)容器為 window 或自定義 DOM 元素;
  • 輕量無依賴:體積小巧(gzip 壓縮后僅 ~3KB),無額外第三方依賴,不增加項(xiàng)目負(fù)擔(dān)。

2. 快速上手:安裝與基礎(chǔ)使用

2.1 安裝依賴

通過 npm 或 yarn 安裝插件(最新版本可參考 npm 官網(wǎng)):

# npm 安裝
npm install react-infinite-scroll-component --save
# yarn 安裝
yarn add react-infinite-scroll-component

2.2 基礎(chǔ)示例:實(shí)現(xiàn)列表無限滾動(dòng)

以下是最基礎(chǔ)的使用場(chǎng)景——滾動(dòng) window 窗口到底部時(shí),自動(dòng)加載更多列表數(shù)據(jù):

import React, { useState, useEffect } from 'react';
import InfiniteScroll from 'react-infinite-scroll-component';
const BasicInfiniteScroll = () => {
  // 1. 狀態(tài)管理:列表數(shù)據(jù)、是否有更多數(shù)據(jù)
  const [list, setList] = useState<number[]>([]);
  const [hasMore, setHasMore] = useState<boolean>(true);
  const [page, setPage] = useState<number>(1); // 分頁參數(shù)
  // 2. 初始化加載第一頁數(shù)據(jù)
  useEffect(() => {
    fetchData(page);
  }, [page]);
  // 3. 模擬接口請(qǐng)求:獲取列表數(shù)據(jù)
  const fetchData = async (currentPage: number) => {
    try {
      // 模擬接口延遲(實(shí)際項(xiàng)目替換為真實(shí)接口請(qǐng)求)
      const response = await new Promise<number[]>((resolve) => {
        setTimeout(() => {
          // 生成 10 條模擬數(shù)據(jù)
          const newData = Array.from({ length: 10 }, (_, i) => (currentPage - 1) * 10 + i + 1);
          resolve(newData);
        }, 800);
      });
      // 更新列表數(shù)據(jù)
      setList(prev => [...prev, ...response]);
      // 控制是否還有更多數(shù)據(jù)(示例:最多加載 5 頁)
      if (currentPage >= 5) {
        setHasMore(false);
      }
    } catch (err) {
      console.error('數(shù)據(jù)加載失?。?, err);
    }
  };
  // 4. 加載更多回調(diào):觸發(fā)下一頁數(shù)據(jù)請(qǐng)求
  const fetchMoreData = () => {
    setPage(prev => prev + 1); // 頁碼 +1,觸發(fā) useEffect 重新請(qǐng)求
  };
  return (
    <div style={{ padding: '20px' }}>
      <h2>基礎(chǔ)無限滾動(dòng)示例</h2>
      {/* 5. 無限滾動(dòng)組件 */}
      <InfiniteScroll
        dataLength={list.length} // 已加載數(shù)據(jù)的長(zhǎng)度(用于判斷是否觸發(fā)加載)
        next={fetchMoreData} // 滾動(dòng)到底部時(shí)觸發(fā)的“加載更多”回調(diào)
        hasMore={hasMore} // 是否還有更多數(shù)據(jù)(false 時(shí)停止觸發(fā) next)
        loader={<h4 style={{ textAlign: 'center', padding: '20px' }}>加載中...</h4>} // 加載中提示組件
        endMessage={
          <p style={{ textAlign: 'center', padding: '20px', color: '#666' }}>
            <b>已加載全部數(shù)據(jù)</b>
          </p>
        } // 無更多數(shù)據(jù)時(shí)的提示
      >
        {/* 6. 列表內(nèi)容 */}
        <ul style={{ listStyle: 'none', padding: 0 }}>
          {list.map((item) => (
            <li
              key={item}
              style={{
                padding: '15px',
                margin: '10px 0',
                border: '1px solid #eee',
                borderRadius: '4px',
              }}
            >
              列表項(xiàng) {item}
            </li>
          ))}
        </ul>
      </InfiniteScroll>
    </div>
  );
};
export default BasicInfiniteScroll;

核心邏輯說明

  1. dataLength:插件通過對(duì)比“已加載數(shù)據(jù)長(zhǎng)度”與“滾動(dòng)容器高度”,判斷是否觸發(fā) next 回調(diào);
  2. next:滾動(dòng)到底部時(shí)執(zhí)行,通常用于更新分頁參數(shù)(如頁碼 +1),進(jìn)而觸發(fā)數(shù)據(jù)請(qǐng)求;
  3. hasMore:控制插件是否繼續(xù)監(jiān)聽滾動(dòng)——當(dāng) hasMore=false 時(shí),不再觸發(fā) next,并顯示 endMessage
  4. loader/endMessage:分別對(duì)應(yīng)“加載中”和“無更多數(shù)據(jù)”的 UI 提示,支持自定義組件。

3. 核心配置項(xiàng)詳解

react-infinite-scroll-component 提供了豐富的配置項(xiàng),可滿足不同場(chǎng)景的需求。以下是常用配置項(xiàng)的分類說明:

3.1 核心功能配置

配置項(xiàng)類型作用默認(rèn)值
dataLengthnumber已加載數(shù)據(jù)的長(zhǎng)度(必傳),插件通過此值判斷是否需要觸發(fā)加載-
next() => void滾動(dòng)到底部時(shí)觸發(fā)的“加載更多”回調(diào)(必傳),用于請(qǐng)求下一頁數(shù)據(jù)-
hasMoreboolean是否還有更多數(shù)據(jù)——false 時(shí)停止觸發(fā) next,并顯示 endMessagetrue
loaderReactNode加載中的提示組件(如“加載中…”文字、Spinner 動(dòng)畫)<h4>Loading...</h4>
endMessageReactNode無更多數(shù)據(jù)時(shí)的提示組件(hasMore=false 時(shí)顯示)-

3.2 滾動(dòng)容器配置

默認(rèn)情況下,插件監(jiān)聽 window 的滾動(dòng)事件;若需監(jiān)聽自定義 DOM 容器的滾動(dòng)(如帶固定高度的列表),需配置以下參數(shù):

配置項(xiàng)類型作用默認(rèn)值
scrollableTargetstring自定義滾動(dòng)容器的 id(需給容器設(shè)置 id 和固定高度 + overflow: auto-
heightstring/number滾動(dòng)容器的高度(僅當(dāng)未指定 scrollableTarget 時(shí)生效,如 500px-
styleCSSProperties滾動(dòng)容器的自定義樣式(如邊框、內(nèi)邊距){}

示例:自定義滾動(dòng)容器

// 自定義滾動(dòng)容器(固定高度 500px,超出滾動(dòng))
<div id="customScrollContainer" style={{ height: '500px', overflow: 'auto', border: '1px solid #eee' }}>
  <InfiniteScroll
    scrollableTarget="customScrollContainer" // 綁定自定義容器的 id
    dataLength={list.length}
    next={fetchMoreData}
    hasMore={hasMore}
    loader={<div style={{ textAlign: 'center', padding: '20px' }}>加載中...</div>}
    endMessage={<div style={{ textAlign: 'center', padding: '20px' }}>已加載全部</div>}
  >
    {/* 列表內(nèi)容 */}
    <ul>
      {list.map(item => (
        <li key={item} style={{ padding: '15px', borderBottom: '1px solid #eee' }}>
          自定義容器列表項(xiàng) {item}
        </li>
      ))}
    </ul>
  </InfiniteScroll>
</div>

3.3 加載觸發(fā)時(shí)機(jī)配置

默認(rèn)情況下,滾動(dòng)到“容器底部”時(shí)觸發(fā)加載;若需提前觸發(fā)(如滾動(dòng)到距離底部 200px 時(shí)開始加載),可通過以下參數(shù)調(diào)整:

配置項(xiàng)類型作用默認(rèn)值
thresholdnumber觸發(fā)加載的“提前距離”(單位:px)——距離底部小于該值時(shí)觸發(fā) next100
disableScrollboolean是否禁用滾動(dòng)監(jiān)聽(如加載失敗時(shí),禁止繼續(xù)觸發(fā)加載)false

示例:提前觸發(fā)加載

<InfiniteScroll
  dataLength={list.length}
  next={fetchMoreData}
  hasMore={hasMore}
  threshold={300} // 距離底部 300px 時(shí)觸發(fā)加載(適合大列表或慢網(wǎng)絡(luò))
  loader={<div>加載中...</div>}
>
  {/* 列表內(nèi)容 */}
</InfiniteScroll>

3.4 其他實(shí)用配置

配置項(xiàng)類型作用默認(rèn)值
onScroll(e: UIEvent) => void滾動(dòng)時(shí)的回調(diào)(可用于自定義滾動(dòng)邏輯,如記錄滾動(dòng)位置)-
initialScrollYnumber初始滾動(dòng)位置(單位:px)——組件掛載時(shí)自動(dòng)滾動(dòng)到指定位置0
reverseboolean是否反向滾動(dòng)(從頂部加載更多,適合聊天記錄等場(chǎng)景)false
pullDownToRefreshboolean是否啟用“下拉刷新”功能(需配合 pullDownToRefreshContentonPullDownRefreshfalse
pullDownToRefreshContentReactNode下拉刷新時(shí)的提示組件(如“下拉可刷新”)<h3>Pull down to refresh</h3>
releaseToRefreshContentReactNode下拉到閾值后釋放時(shí)的提示組件(如“釋放即可刷新”)<h3>Release to refresh</h3>
onPullDownRefresh() => void下拉刷新觸發(fā)的回調(diào)(需手動(dòng)調(diào)用 setPullDownToRefresh(false) 結(jié)束刷新)-

4. 場(chǎng)景化進(jìn)階示例

4.1 反向滾動(dòng):聊天記錄場(chǎng)景

聊天記錄通常需要“從底部向上加載歷史消息”(新消息在底部,滾動(dòng)到頂部時(shí)加載更早的記錄),可通過 reverse 配置實(shí)現(xiàn):

import React, { useState, useEffect } from 'react';
import InfiniteScroll from 'react-infinite-scroll-component';
const ChatInfiniteScroll = () => {
  const [messages, setMessages] = useState<string[]>([]);
  const [hasMore, setHasMore] = useState<boolean>(true);
  const [page, setPage] = useState<number>(1);
  // 初始化加載最新消息(第 1 頁)
  useEffect(() => {
    fetchChatHistory(page);
  }, [page]);
  // 模擬加載聊天歷史記錄(頁號(hào)越小,消息越新)
  const fetchChatHistory = async (currentPage: number) => {
    await new Promise<void>((resolve) => {
      setTimeout(() => {
        const newMessages = Array.from({ length: 5 }, (_, i) => 
          `歷史消息 ${(currentPage - 1) * 5 + i + 1}(頁 ${currentPage})`
        );
        setMessages(prev => [...newMessages, ...prev]); // 新消息添加到數(shù)組頭部(反向)
        // 最多加載 4 頁歷史消息
        if (currentPage >= 4) {
          setHasMore(false);
        }
        resolve();
      }, 800);
    });
  };
  // 滾動(dòng)到頂部時(shí)加載更多歷史消息
  const fetchMoreHistory = () => {
    setPage(prev => prev + 1);
  };
  return (
    <div style={{ height: '600px', border: '1px solid #eee', borderRadius: '4px' }}>
      <h3 style={{ padding: '10px', borderBottom: '1px solid #eee' }}>聊天窗口</h3>
      {/* 反向滾動(dòng)容器 */}
      <InfiniteScroll
        scrollableTarget="chatContainer" // 自定義滾動(dòng)容器 id
        dataLength={messages.length}
        next={fetchMoreHistory}
        hasMore={hasMore}
        reverse={true} // 啟用反向滾動(dòng)(頂部加載更多)
        loader={<div style={{ textAlign: 'center', padding: '10px' }}>加載更早的消息...</div>}
        endMessage={<div style={{ textAlign: 'center', padding: '10px', color: '#666' }}>已加載全部歷史消息</div>}
      >
        <div id="chatContainer" style={{ height: '540px', overflow: 'auto', padding: '10px' }}>
          {messages.map((msg, index) => (
            <div
              key={index}
              style={{
                margin: '8px 0',
                padding: '8px 12px',
                backgroundColor: '#f5f5f5',
                borderRadius: '8px',
                maxWidth: '80%',
              }}
            >
              {msg}
            </div>
          ))}
        </div>
      </InfiniteScroll>
    </div>
  );
};
export default ChatInfiniteScroll;

核心邏輯

  • reverse={true}:插件監(jiān)聽“滾動(dòng)到頂部”事件,觸發(fā) next 加載歷史數(shù)據(jù);
  • 新加載的歷史消息通過 [...newMessages, ...prev] 添加到數(shù)組頭部,確保 UI 中“歷史消息在上方,最新消息在下方”。

4.2 下拉刷新 + 無限滾動(dòng)

結(jié)合“下拉刷新”(更新最新數(shù)據(jù))和“無限滾動(dòng)”(加載更多歷史數(shù)據(jù)),滿足列表的完整交互需求:

const PullRefreshAndInfinite = () => {
  const [list, setList] = useState<number[]>([]);
  const [hasMore, setHasMore] = useState<boolean>(true);
  const [page, setPage] = useState<number>(1);
  const [pullDownToRefresh, setPullDownToRefresh] = useState<boolean>(false); // 控制下拉刷新狀態(tài)
  // 初始化加載
  useEffect(() => {
    fetchData(page);
  }, [page]);
  // 加載列表數(shù)據(jù)
  const fetchData = async (currentPage: number) => {
    await new Promise<void>((resolve) => {
      setTimeout(() => {
        const newData = Array.from({ length: 10 }, (_, i) => (currentPage - 1) * 10 + i + 1);
        setList(prev => currentPage === 1 ? newData : [...prev, ...newData]); // 第一頁覆蓋,后續(xù)頁追加
        setHasMore(currentPage < 5);
        resolve();
      }, 800);
    });
  };
  // 加載更多(滾動(dòng)到底部)
  const fetchMoreData = () => {
    setPage(prev => prev + 1);
  };
  // 下拉刷新(更新最新數(shù)據(jù))
  const handlePullDownRefresh = async () => {
    setPullDownToRefresh(true); // 顯示“刷新中”狀態(tài)
    await fetchData(1); // 重新請(qǐng)求第一頁數(shù)據(jù)(最新數(shù)據(jù))
    setPullDownToRefresh(false); // 結(jié)束刷新
  };
  return (
    <InfiniteScroll
      dataLength={list.length}
      next={fetchMoreData}
      hasMore={hasMore}
      loader={<div style={{ textAlign: 'center', padding: '20px' }}>加載中...</div>}
      endMessage={<div style={{ textAlign: 'center', padding: '20px' }}>已加載全部</div>}
      // 下拉刷新配置
      pullDownToRefresh={pullDownToRefresh}
      pullDownToRefreshContent={<div style={{ textAlign: 'center', padding: '20px' }}>下拉可刷新</div>}
      releaseToRefreshContent={<div style={{ textAlign: 'center', padding: '20px' }}>釋放即可刷新</div>}
      onPullDownRefresh={handlePullDownRefresh}
    >
      <ul style={{ listStyle: 'none', padding: '0 20px' }}>
        {list.map(item => (
          <li
            key={item}
            style={{ padding: '15px', margin: '10px 0', borderBottom: '1px solid #eee' }}
          >
            帶下拉刷新的列表項(xiàng) {item}
          </li>
        ))}
      </ul>
    </InfiniteScroll>
  );
};
export default PullRefreshAndInfinite;

核心邏輯

  • pullDownToRefresh:控制下拉刷新狀態(tài)(true 時(shí)顯示刷新中 UI,禁止重復(fù)觸發(fā));
  • onPullDownRefresh:下拉到閾值并釋放后觸發(fā),通常用于重新請(qǐng)求第一頁數(shù)據(jù)(獲取最新內(nèi)容);
  • 數(shù)據(jù)更新時(shí)需將 pullDownToRefresh 設(shè)為 false,否則刷新狀態(tài)會(huì)一直保持。

4.3 加載失敗重試

實(shí)際項(xiàng)目中可能出現(xiàn)接口請(qǐng)求失敗的情況,需提供“重試加載”功能,可通過狀態(tài)管理控制加載狀態(tài)與重試邏輯:

const RetryOnFail = () => {
  const [list, setList] = useState<number[]>([]);
  const [hasMore, setHasMore] = useState<boolean>(true);
  const [page, setPage] = useState<number>(1);
  const [isLoading, setIsLoading] = useState<boolean>(false); // 加載中狀態(tài)(防止重復(fù)請(qǐng)求)
  const [loadError, setLoadError] = useState<boolean>(false); // 加載失敗狀態(tài)
  // 初始化加載
  useEffect(() => {
    fetchData(page);
  }, [page]);
  // 數(shù)據(jù)請(qǐng)求邏輯(含失敗處理)
  const fetchData = async (currentPage: number) => {
    setIsLoading(true);
    setLoadError(false); // 重置失敗狀態(tài)
    try {
      const response = await new Promise<number[]>((resolve, reject) => {
        setTimeout(() => {
          // 模擬 30% 概率請(qǐng)求失敗
          if (Math.random() < 0.3) {
            reject(new Error('接口請(qǐng)求失敗'));
          } else {
            const newData = Array.from({ length: 10 }, (_, i) => (currentPage - 1) * 10 + i + 1);
            resolve(newData);
          }
        }, 800);
      });
      setList(prev => [...prev, ...response]);
      setHasMore(currentPage < 5);
    } catch (err) {
      console.error('加載失敗:', err);
      setLoadError(true); // 標(biāo)記加載失敗
    } finally {
      setIsLoading(false); // 結(jié)束加載狀態(tài)
    }
  };
  // 加載更多(僅當(dāng)非加載中、非失敗時(shí)觸發(fā))
  const fetchMoreData = () => {
    if (!isLoading && !loadError) {
      setPage(prev => prev + 1);
    }
  };
  // 重試加載當(dāng)前頁
  const retryLoad = () => {
    fetchData(page);
  };
  return (
    <InfiniteScroll
      dataLength={list.length}
      next={fetchMoreData}
      hasMore={hasMore && !loadError} // 失敗時(shí)停止觸發(fā)自動(dòng)加載
      disableScroll={isLoading || loadError} // 加載中/失敗時(shí)禁用滾動(dòng)觸發(fā)
      // 加載中/失敗 UI 切換
      loader={isLoading ? <div style={{ textAlign: 'center', padding: '20px' }}>加載中...</div> : null}
      endMessage={
        hasMore ? null : (
          <div style={{ textAlign: 'center', padding: '20px', color: '#666' }}>已加載全部數(shù)據(jù)</div>
        )
      }
    >
      <ul style={{ listStyle: 'none', padding: '0 20px' }}>
        {list.map(item => (
          <li
            key={item}
            style={{ padding: '15px', margin: '10px 0', border: '1px solid #eee', borderRadius: '4px' }}
          >
            支持重試的列表項(xiàng) {item}
          </li>
        ))}
        {/* 加載失敗提示與重試按鈕 */}
        {loadError && (
          <div style={{ textAlign: 'center', padding: '20px' }}>
            <p style={{ color: 'red' }}>加載失敗,請(qǐng)重試</p>
            <button
              onClick={retryLoad}
              style={{
                padding: '8px 16px',
                margin: '10px 0',
                border: 'none',
                backgroundColor: '#007bff',
                color: 'white',
                borderRadius: '4px',
                cursor: 'pointer',
              }}
            >
              重試加載
            </button>
          </div>
        )}
      </ul>
    </InfiniteScroll>
  );
};
export default RetryOnFail;

核心邏輯

  • isLoading:防止?jié)L動(dòng)時(shí)重復(fù)觸發(fā)請(qǐng)求(加載中時(shí)禁用 next);
  • loadError:標(biāo)記請(qǐng)求失敗狀態(tài),顯示重試按鈕,同時(shí)停止自動(dòng)加載;
  • retryLoad:重試時(shí)重新請(qǐng)求當(dāng)前頁數(shù)據(jù),而非直接請(qǐng)求下一頁,確保數(shù)據(jù)連續(xù)性。

5. 性能優(yōu)化建議

無限滾動(dòng)場(chǎng)景若處理不當(dāng),可能導(dǎo)致列表渲染性能下降(如 DOM 元素過多、重復(fù)渲染),以下是關(guān)鍵優(yōu)化點(diǎn):

5.1 實(shí)現(xiàn)列表項(xiàng)虛擬滾動(dòng)

當(dāng)列表數(shù)據(jù)量極大(如超過 100 條)時(shí),直接渲染所有 DOM 元素會(huì)占用大量?jī)?nèi)存,導(dǎo)致頁面卡頓。建議結(jié)合 react-windowreact-virtualized 實(shí)現(xiàn)“虛擬滾動(dòng)”(僅渲染可視區(qū)域內(nèi)的列表項(xiàng))。

示例:結(jié)合 react-window 優(yōu)化

# 安裝 react-window
npm install react-window --save
import { FixedSizeList as List } from 'react-window';
import InfiniteScroll from 'react-infinite-scroll-component';
const VirtualizedInfiniteScroll = () => {
  const [list, setList] = useState<number[]>([]);
  const [hasMore, setHasMore] = useState<boolean>(true);
  const [page, setPage] = useState<number>(1);
  // 數(shù)據(jù)請(qǐng)求邏輯(同前)
  useEffect(() => {
    fetchData(page);
  }, [page]);
  const fetchData = async (currentPage: number) => {
    // 模擬數(shù)據(jù)請(qǐng)求...
    const newData = Array.from({ length: 20 }, (_, i) => (currentPage - 1) * 20 + i + 1);
    setList(prev => [...prev, ...newData]);
    setHasMore(currentPage < 10);
  };
  const fetchMoreData = () => {
    setPage(prev => prev + 1);
  };
  // 渲染單個(gè)列表項(xiàng)(react-window 要求)
  const renderListItem = ({ index, style }: { index: number; style: React.CSSProperties }) => {
    const item = list[index];
    return (
      <div style={{ ...style, padding: '15px', borderBottom: '1px solid #eee' }}>
        虛擬滾動(dòng)列表項(xiàng) {item}
      </div>
    );
  };
  return (
    <InfiniteScroll
      dataLength={list.length}
      next={fetchMoreData}
      hasMore={hasMore}
      loader={<div style={{ textAlign: 'center', padding: '20px' }}>加載中...</div>}
      endMessage={<div style={{ textAlign: 'center', padding: '20px' }}>已加載全部</div>}
    >
      {/* 虛擬滾動(dòng)列表:僅渲染可視區(qū)域內(nèi)的項(xiàng)(高度 500px,每項(xiàng)高度 60px) */}
      <List
        height={500}
        width="100%"
        itemCount={list.length}
        itemSize={60} // 每項(xiàng)固定高度
      >
        {renderListItem}
      </List>
    </InfiniteScroll>
  );
};
export default VirtualizedInfiniteScroll;

優(yōu)化原理:react-window 通過計(jì)算可視區(qū)域范圍,僅渲染“能看到的列表項(xiàng)”,即使列表有 1000 條數(shù)據(jù),DOM 元素?cái)?shù)量也僅為“可視區(qū)域高度 / 每項(xiàng)高度”(通常 10 條左右),大幅降低渲染壓力。

5.2 避免重復(fù)請(qǐng)求

  • isLoading 狀態(tài)控制:請(qǐng)求發(fā)起時(shí)設(shè)為 true,請(qǐng)求結(jié)束(成功/失敗)后設(shè)為 false,next 回調(diào)中判斷 !isLoading 才觸發(fā)下一次請(qǐng)求;
  • 限制請(qǐng)求頻率:避免快速滾動(dòng)時(shí)頻繁觸發(fā) next(插件內(nèi)部已做防抖,但可結(jié)合 threshold 增大提前加載距離,減少請(qǐng)求次數(shù))。

5.3 優(yōu)化數(shù)據(jù)更新邏輯

  • 避免直接修改原數(shù)組:使用 setList(prev => [...prev, ...newData]) 而非 list.push(...newData),確保 React 能正確識(shí)別狀態(tài)變化;
  • 分頁數(shù)據(jù)去重:若接口可能返回重復(fù)數(shù)據(jù)(如分頁參數(shù)異常),可在更新列表前通過 Setfilter 去重:
    setList(prev => {
      const uniqueData = [...new Set([...prev, ...newData])];
      return uniqueData;
    });

5.4 減少不必要的重渲染

  • 列表項(xiàng)用 memo 包裹:若列表項(xiàng)為自定義組件,且 props 不變時(shí)無需重渲染,可通過 React.memo 優(yōu)化:
    const ListItem = React.memo(({ item }: { item: number }) => {
      return <div style={{ padding: '15px' }}>列表項(xiàng) {item}</div>;
    });
  • 避免在渲染中定義函數(shù):將 fetchMoreData、retryLoad 等函數(shù)用 useCallback 包裹,防止每次渲染生成新函數(shù)導(dǎo)致子組件重渲染:
    const fetchMoreData = useCallback(() => {
      if (!isLoading && !loadError) {
        setPage(prev => prev + 1);
      }
    }, [isLoading, loadError]);

6. 常見問題與解決方案

6.1 滾動(dòng)不觸發(fā)加載?

  • 檢查 dataLength:必須正確傳遞“已加載數(shù)據(jù)的長(zhǎng)度”,插件通過 dataLength 判斷“是否已滾動(dòng)到可加載位置”(若 dataLength=0,可能因“無數(shù)據(jù)可滾動(dòng)”無法觸發(fā));
  • 確認(rèn)滾動(dòng)容器:若用 scrollableTarget,需確保容器設(shè)置了 idoverflow: auto + 固定高度(無固定高度則容器會(huì)被內(nèi)容撐滿,無法滾動(dòng));
  • 檢查 hasMore:若初始 hasMore=false,插件會(huì)直接顯示 endMessage,不觸發(fā) next;
  • 查看控制臺(tái)報(bào)錯(cuò):若存在 JS 錯(cuò)誤(如 fetchData 未定義),會(huì)導(dǎo)致 next 回調(diào)執(zhí)行失敗,需優(yōu)先修復(fù)錯(cuò)誤。

6.2 加載后列表不滾動(dòng)到底部?

  • 反向滾動(dòng)場(chǎng)景(reverse=true):加載歷史消息后,需手動(dòng)滾動(dòng)到“加載前的位置”(避免每次加載都跳到頂部),可通過 scrollableTarget 對(duì)應(yīng)的 DOM 元素控制:
    const chatContainer = document.getElementById('chatContainer');
    if (chatContainer) {
      const scrollTop = chatContainer.scrollTop; // 記錄加載前的滾動(dòng)位置
      // 數(shù)據(jù)更新后恢復(fù)滾動(dòng)位置
      setTimeout(() => {
        chatContainer.scrollTop = scrollTop;
      }, 0);
    }
  • 正常滾動(dòng)場(chǎng)景:若需加載后自動(dòng)滾動(dòng)到底部,可在 setList 后調(diào)用 scrollTo
    setList(prev => [...prev, ...newData], () => {
      window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' });
    });

6.3 下拉刷新不生效?

  • 確保配置完整:需同時(shí)設(shè)置 pullDownToRefresh(控制狀態(tài))、onPullDownRefresh(回調(diào))、pullDownToRefreshContent(提示 UI);
  • onPullDownRefresh 中必須重置狀態(tài):回調(diào)執(zhí)行完后需將 pullDownToRefresh 設(shè)為 false,否則刷新狀態(tài)會(huì)一直保持;
  • 檢查滾動(dòng)容器:下拉刷新僅支持 window 滾動(dòng)或“高度固定且可滾動(dòng)的容器”,若容器無固定高度,可能無法觸發(fā)下拉邏輯。

6.4 移動(dòng)端滾動(dòng)不流暢?

  • 關(guān)閉觸摸事件阻止:若項(xiàng)目中存在 touchmove 事件阻止默認(rèn)行為(如 e.preventDefault()),可能影響移動(dòng)端滾動(dòng),需在滾動(dòng)容器內(nèi)放行觸摸事件;
  • 優(yōu)化列表項(xiàng)樣式:避免使用復(fù)雜 CSS(如 box-shadow、gradient)或大量圖片,可通過 will-change: transform 提示瀏覽器提前優(yōu)化渲染:

7. 總結(jié)

react-infinite-scroll-component 是一款“開箱即用”的無限滾動(dòng)插件,其核心價(jià)值在于簡(jiǎn)化底層滾動(dòng)邏輯,讓開發(fā)者專注于數(shù)據(jù)處理與 UI 設(shè)計(jì)。通過本文的講解,可掌握:

  1. 基礎(chǔ)用法:快速實(shí)現(xiàn)“滾動(dòng)加載更多”,配置 dataLengthnext、hasMore 核心參數(shù);
  2. 場(chǎng)景進(jìn)階:處理反向滾動(dòng)(聊天記錄)、下拉刷新、加載失敗重試等實(shí)際需求;
  3. 性能優(yōu)化:結(jié)合虛擬滾動(dòng)、避免重復(fù)請(qǐng)求、減少重渲染,確保大列表流暢運(yùn)行;
  4. 問題排查:解決滾動(dòng)不觸發(fā)、加載異常等常見問題。

適用場(chǎng)景包括:商品列表、文章列表、聊天記錄、數(shù)據(jù)報(bào)表等“需要批量加載數(shù)據(jù)且滾動(dòng)查看”的界面。在實(shí)際項(xiàng)目中,建議根據(jù)數(shù)據(jù)量大小選擇是否結(jié)合虛擬滾動(dòng),并始終關(guān)注“用戶體驗(yàn)”(如加載狀態(tài)提示、失敗重試、避免卡頓),讓無限滾動(dòng)既實(shí)用又流暢。

到此這篇關(guān)于React無限滾動(dòng)插件react-infinite-scroll-component的配置優(yōu)化技巧的文章就介紹到這了,更多相關(guān)react滾動(dòng)插件react-infinite-scroll-component內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Create?react?app修改webapck配置導(dǎo)入文件alias

    Create?react?app修改webapck配置導(dǎo)入文件alias

    這篇文章主要為大家介紹了Create?react?app修改webapck配置導(dǎo)入文件alias,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • React使用高階組件與Hooks實(shí)現(xiàn)權(quán)限攔截教程詳細(xì)分析

    React使用高階組件與Hooks實(shí)現(xiàn)權(quán)限攔截教程詳細(xì)分析

    高階組件就是接受一個(gè)組件作為參數(shù)并返回一個(gè)新組件(功能增強(qiáng)的組件)的函數(shù)。這里需要注意高階組件是一個(gè)函數(shù),并不是組件,這一點(diǎn)一定要注意,本文給大家分享React高階組件使用小結(jié),一起看看吧
    2023-01-01
  • React配置代理方式(proxy)

    React配置代理方式(proxy)

    這篇文章主要介紹了React配置代理方式(proxy),具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • react 項(xiàng)目 中使用 Dllplugin 打包優(yōu)化技巧

    react 項(xiàng)目 中使用 Dllplugin 打包優(yōu)化技巧

    在用 Webpack 打包的時(shí)候,對(duì)于一些不經(jīng)常更新的第三方庫,比如 react,lodash,vue 我們希望能和自己的代碼分離開,這篇文章主要介紹了react 項(xiàng)目 中 使用 Dllplugin 打包優(yōu)化,需要的朋友可以參考下
    2023-01-01
  • 聊聊ant?design?charts?獲取后端接口數(shù)據(jù)展示問題

    聊聊ant?design?charts?獲取后端接口數(shù)據(jù)展示問題

    今天在做項(xiàng)目的時(shí)候遇到幾個(gè)讓我很頭疼的問題,一個(gè)是通過后端接口成功訪問并又返回?cái)?shù)據(jù),但拿不到數(shù)據(jù)值。其二是直接修改state中的data,console中數(shù)組發(fā)生變化但任然數(shù)據(jù)未顯示,這篇文章主要介紹了ant?design?charts?獲取后端接口數(shù)據(jù)展示,需要的朋友可以參考下
    2022-05-05
  • React如何避免重渲染

    React如何避免重渲染

    這篇文章主要介紹了React如何避免重渲染,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-04-04
  • React簡(jiǎn)便獲取經(jīng)緯度信息的方法詳解

    React簡(jiǎn)便獲取經(jīng)緯度信息的方法詳解

    在現(xiàn)代的Web應(yīng)用程序中,獲取用戶的地理位置信息是一項(xiàng)常見的需求,本文我們將介紹如何在React應(yīng)用程序中簡(jiǎn)便地獲取用戶的經(jīng)緯度信息,需要的可以參考下
    2023-11-11
  • 需要避免的五個(gè)react的ref錯(cuò)誤用法

    需要避免的五個(gè)react的ref錯(cuò)誤用法

    react是一個(gè)優(yōu)秀的框架,提供了我們很多的便利,但是在使用的過程中,我們也會(huì)遇到很多的問題,其中一個(gè)就是ref的使用,以下是我列出的5個(gè)使用ref的錯(cuò)誤用法,并提供了正確的用法,需要的朋友可以參考下
    2024-12-12
  • React通過hook實(shí)現(xiàn)封裝表格常用功能

    React通過hook實(shí)現(xiàn)封裝表格常用功能

    這篇文章主要為大家詳細(xì)介紹了React通過hook封裝表格常用功能的使用,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,有需要的小伙伴可以參考下
    2023-12-12
  • 基于visual studio code + react 開發(fā)環(huán)境搭建過程

    基于visual studio code + react 開發(fā)環(huán)境搭建過程

    今天通過本文給大家分享基于visual studio code + react 開發(fā)環(huán)境搭建過程,本文給大家介紹的非常詳細(xì),包括react安裝問題及安裝 Debugger for Chrome的方法,需要的朋友跟隨小編一起看看吧
    2021-07-07

最新評(píng)論