You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React函数式组件中使用react-infinite-scroll-component实现按10条递增的无限滚动异常问题排查

React函数式组件中使用react-infinite-scroll-component实现按10条递增的无限滚动异常问题排查

我太懂你这种懵圈的感觉了——本来想实现每次加载10条的无限滚动,结果数组直接一次性全出来,还看了一堆类组件的数组状态修改文章越看越乱,别慌,咱们把问题拆开来解决。

核心问题分析

你现在的情况大概率是两个原因:

  1. 没有维护**“已加载条目数”**的状态,每次更新直接把完整数组塞进去了,没有做分批截取;
  2. 可能对React函数式组件里数组状态的不可变更新理解不到位,不小心直接修改了原数组导致状态更新异常。

解决方案步骤&代码示例

咱们直接上能跑的逻辑,核心是要分开维护「完整数据源」和「当前展示数据」两个状态,配合组件的next方法实现分批加载:

import { useState, useEffect } from 'react';
import InfiniteScroll from 'react-infinite-scroll-component';

function InfiniteScrollDemo() {
  // 存储所有要展示的完整数据(实际项目里这里是接口返回的全量数据)
  const [fullData, setFullData] = useState([]);
  // 当前页面要渲染的数据,每次追加10条
  const [displayData, setDisplayData] = useState([]);
  // 标记是否还有更多数据可以加载
  const [hasMore, setHasMore] = useState(true);

  // 模拟从接口获取全量数据(实际项目替换成你的异步请求)
  useEffect(() => {
    // 生成100条模拟数据,方便测试
    const mockFullData = Array.from({ length: 100 }, (_, idx) => `第${idx + 1}条数据`);
    setFullData(mockFullData);
    // 初始加载前10条
    setDisplayData(mockFullData.slice(0, 10));
  }, []);

  // 滚动到底部时触发的加载逻辑,你要的5秒延迟也在这里
  const loadMore = () => {
    setTimeout(() => {
      // 计算下一批要加载的截止位置
      const nextLoadEnd = displayData.length + 10;
      // 从全量数据里截取新的展示数据
      const newDisplayData = fullData.slice(0, nextLoadEnd);
      
      setDisplayData(newDisplayData);
      
      // 判断是否已经加载完所有数据
      if (newDisplayData.length >= fullData.length) {
        setHasMore(false);
      }
    }, 5000); // 这里设置5秒延迟,和你需求一致
  };

  return (
    <InfiniteScroll
      // 必须设置为当前展示数据的长度,组件靠这个判断是否触发加载
      dataLength={displayData.length}
      next={loadMore}
      hasMore={hasMore}
      loader={<h4>正在加载下一批...</h4>}
      endMessage={<p style={{textAlign: 'center'}}>所有数据已加载完毕 😊</p>}
    >
      <div className="data-list">
        {displayData.map((item, idx) => (
          <div key={idx} style={{padding: '12px', borderBottom: '1px solid #eee'}}>
            {item}
          </div>
        ))}
      </div>
    </InfiniteScroll>
  );
}

export default InfiniteScrollDemo;

关键细节说明

  1. 状态拆分:用fullData存全量数据,displayData存当前要渲染的分批数据,这样每次加载只需要从全量数据里截取新的部分,不会一次性全渲染;
  2. 不可变更新:用slice方法创建新数组(而不是直接修改原数组),React能通过新数组的引用变化检测到状态更新,从而触发重新渲染;
  3. 组件属性配置:dataLength必须对应displayData.length,这是组件判断是否滚动到底部的关键;hasMore用来控制是否继续触发加载逻辑;
  4. 延迟加载:用setTimeout模拟你要的5秒加载间隔,实际项目里这里就是你的异步请求逻辑。

关于你提到的类组件文章

那些文章讲的核心其实和函数式组件一致:永远不要直接修改原状态数组,必须通过创建新数组的方式更新状态(比如slice、concat或者扩展运算符[...prevData])。你之前可能不小心用了push这种直接修改原数组的操作,导致React没检测到状态变化,或者更新逻辑异常。

你可能踩的坑

  • 直接把全量数组赋值给displayData,没有做分批截取;
  • dataLength设置成了全量数组的长度,导致组件认为已经加载完所有数据,不会触发分批加载;
  • 状态更新时直接修改了原数组,没有遵循不可变原则。

备注:内容来源于stack exchange,提问作者nuser137

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.22 10:29:34