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

React滚动加载产品问题:如何实现初始10条+滚动触发加载10条

修复无限滚动初始加载全部数据的问题

你的问题核心在于初始请求一次性获取了所有产品,而非分页加载。要实现「初始加载10条,滚动到底部再加载10条」的效果,需从「前端分页请求」和「滚动触发逻辑优化」两方面修改:

1. 后端API支持分页参数(必要前提)

首先需要你的后端接口支持分页,接收page(页码)和limit(每页数量)参数,返回对应页的产品数据,以及总页数/总产品数(用于判断是否还有更多数据)。示例返回格式:

{
  "products": [/* 当前页10条产品数据 */],
  "totalPages": 2, // 总页数
  "totalCount": 20 // 总产品数
}

2. 前端代码修改

调整状态管理

新增分页相关状态,替换原有的productCount:

const Products = ({ cat, filters, sort }) => {
  const [products, setProducts] = useState([]);
  const [filteredProducts, setFilteredProducts] = useState([]);
  const [currentPage, setCurrentPage] = useState(1); // 当前请求页码
  const [isLoading, setIsLoading] = useState(false); // 加载状态,避免重复请求
  const [hasMore, setHasMore] = useState(true); // 是否还有更多数据可加载

  const myRef = useRef(null);

修改初始请求逻辑,实现分页加载

将一次性请求所有产品改为分页请求,初始仅请求第1页(10条):

// 切换分类时重置分页状态
useEffect(() => {
  setCurrentPage(1);
  setProducts([]);
  setHasMore(true);
}, [cat]);

useEffect(() => {
  const getProducts = async () => {
    if (!hasMore) return; // 无更多数据时终止请求
    setIsLoading(true);
    try {
      // 拼接分页参数
      const url = cat
        ? `http://localhost:5000/api/products?category=${cat}&page=${currentPage}&limit=10`
        : `http://localhost:5000/api/products/?page=${currentPage}&limit=10`;
      
      const res = await axiosInstance.get(url);
      // 追加新数据,而非替换原有数据
      setProducts(prevProducts => [...prevProducts, ...res.data.products]);
      // 判断是否还有更多数据(总页数大于当前页)
      setHasMore(res.data.totalPages > currentPage);
    } catch (err) {
      console.error('加载产品失败:', err);
    } finally {
      setIsLoading(false);
    }
  };
  getProducts();
}, [cat, currentPage]); // 页码变化时自动请求下一页

优化滚动触发逻辑

添加加载状态和无更多数据的判断,避免重复请求和无效触发:

const handleScroll = () => {
  // 加载中或无更多数据时,不触发新请求
  if (isLoading || !hasMore) return;
  
  if (
    myRef.current &&
    // 加100px偏移量,提前触发加载提升体验
    myRef.current.getBoundingClientRect().bottom <= window.innerHeight + 100
  ) {
    setCurrentPage(prevPage => prevPage + 1);
  }
};

useEffect(() => {
  window.addEventListener("scroll", handleScroll);
  return () => {
    window.removeEventListener("scroll", handleScroll);
  };
}, [isLoading, hasMore]); // 依赖加载状态和是否有更多数据

渲染逻辑说明

现在products数组是累计加载的,渲染时直接使用该数组即可。如果需要过滤/排序,基于products处理filteredProducts:

// 示例:根据filters和sort处理过滤排序
useEffect(() => {
  let result = [...products];
  // 应用过滤逻辑
  if (filters) {
    // 你的过滤代码
  }
  // 应用排序逻辑
  if (sort) {
    // 你的排序代码
  }
  setFilteredProducts(result);
}, [products, filters, sort]);

关键修复点总结

  • 从「一次性获取全部数据」改为「分页请求数据」,初始仅加载第1页
  • 用currentPage控制请求页码,滚动到底部时递增页码触发下一页请求
  • 添加isLoading和hasMore状态,避免重复请求和无效触发
  • 切换分类时重置分页状态,保证新分类从第1页开始加载

内容的提问来源于stack exchange,提问作者Ilan Edri

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 07:05:41