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

从零开始在ReactJS中实现无限滚动(不依赖第三方库)

React 从零实现无限滚动(无第三方库)

核心思路

通过状态控制当前渲染的条目数量,监听页面滚动事件,当滚动到接近底部时,增加显示的条目数,实现分批加载效果。

具体实现步骤

1. 添加状态管理

在组件中新增状态控制显示条目数和加载状态,同时保留你的原始数据状态:

import { useState, useEffect, useRef } from 'react';

function YourComponent() {
  const [data, setData] = useState([]); // 你的原始JSON数据
  const [visibleItems, setVisibleItems] = useState(10); // 初始显示10条,可自定义
  const [isLoading, setIsLoading] = useState(false);
  const scrollRef = useRef(null); // 可选,用于监听容器内滚动

  // 加载JSON数据的逻辑
  useEffect(() => {
    const fetchData = async () => {
      const res = await fetch('/your-data-source.json');
      const jsonData = await res.json();
      setData(jsonData);
    };
    fetchData();
  }, []);

  // 后续逻辑...
}

2. 实现滚动监听逻辑

添加滚动监听,判断是否到达加载触发点,触发时增加显示条目数:

useEffect(() => {
  const handleScroll = () => {
    // 正在加载或已显示全部数据时,直接返回
    if (isLoading || visibleItems >= data.length) return;

    // 计算页面滚动参数(如果是容器内滚动,替换为scrollRef.current的属性)
    const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
    const scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight;
    const clientHeight = document.documentElement.clientHeight || window.innerHeight;

    // 距离底部200px时触发加载(可自定义触发距离)
    if (scrollTop + clientHeight >= scrollHeight - 200) {
      setIsLoading(true);
      // 模拟加载延迟(实际项目中如果是异步请求新数据,这里替换为请求逻辑)
      setTimeout(() => {
        // 每次加载10条,不超过总数据量
        setVisibleItems(prev => Math.min(prev + 10, data.length));
        setIsLoading(false);
      }, 500);
    }
  };

  window.addEventListener('scroll', handleScroll);
  // 组件卸载时清理监听
  return () => window.removeEventListener('scroll', handleScroll);
}, [isLoading, visibleItems, data.length]);

3. 修改渲染逻辑

只渲染visibleItems数量的条目,替换你原来的全量渲染代码:

return (
  <div ref={scrollRef}> {/* 如果是容器内滚动,给容器添加这个ref */}
    {data.slice(0, visibleItems).map((conto) => (
      <Suspense key={conto._uid} fallback={<p>Loading...</p>}>
        <Conto 
          blok={conto} 
          data={data} 
          ITEuro={ITEuro} 
          deposit={deposit} 
          handleToggleFavourite={handleToggleFavourite} 
          isFavourited={isFavourited} 
          depositQuantity={depositQuantity} 
        />
      </Suspense>
    ))}

    {/* 加载状态提示 */}
    {isLoading && <p>加载更多...</p>}
    {/* 无更多数据提示 */}
    {visibleItems >= data.length && !isLoading && <p>已加载全部数据</p>}
  </div>
);

4. 容器内滚动适配(可选)

如果列表在固定高度的容器内滚动,只需修改滚动监听的目标元素:

useEffect(() => {
  const container = scrollRef.current;
  if (!container) return;

  const handleScroll = () => {
    if (isLoading || visibleItems >= data.length) return;

    const { scrollTop, scrollHeight, clientHeight } = container;
    if (scrollTop + clientHeight >= scrollHeight - 200) {
      setIsLoading(true);
      setTimeout(() => {
        setVisibleItems(prev => Math.min(prev + 10, data.length));
        setIsLoading(false);
      }, 500);
    }
  };

  container.addEventListener('scroll', handleScroll);
  return () => container.removeEventListener('scroll', handleScroll);
}, [isLoading, visibleItems, data.length]);

关键优化点

  • 防抖处理:如果滚动事件触发过于频繁,可给handleScroll添加防抖逻辑(比如用setTimeout限制100ms内只触发一次),减少性能消耗。
  • 边界判断:始终用Math.min控制visibleItems不超过总数据长度,避免数组越界报错。
  • 内存清理:组件卸载时务必移除滚动监听,防止内存泄漏。

内容的提问来源于stack exchange,提问作者Michele Bordiga

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 22:05:07