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

React Infinite Scroll问题:fetchNextPage未触发,无法加载更多数据

React无限滚动不触发加载的问题修复

你的代码存在几个关键问题导致fetchNextPage未被调用,以下是具体修复方案:

1. 滚动容器无触发条件

react-infinite-scroll-component需要内容高度超过可视区域才会触发next回调。如果当前渲染的10条内容不足以撑满页面,不会出现滚动条,组件也就不会触发加载。

  • 修复:给外层容器添加最小高度样式,确保页面可滚动:
    <div className="min-h-screen">
      {/* 原内容 */}
    </div>
    

2. 状态更新的闭包陷阱

fetchNextPage中直接使用firstId、lastId和pages更新状态时,会因为闭包问题拿到旧的状态值,导致分页逻辑错误。

  • 修复:使用函数式状态更新获取最新状态:
    const fetchNextPage = () => {
      const result = items.slice(firstId, lastId);
      setPages(prevPages => [...prevPages, ...result]);
      if (result.length === 0 || result.length < 10) {
        setHasMore(false);
      }
      setFirstId(prev => prev + 10);
      setLastId(prev => prev + 10);
    };
    

3. 分类切换时未重置分页状态

当categoryId变化重新拉取数据时,firstId、lastId和hasMore没有重置,导致分页逻辑混乱,同时原代码中依赖items的useEffect会覆盖pages但未同步更新分页游标。

  • 修复:合并分页初始化逻辑到数据加载的useEffect中,去掉多余的useEffect:
    useEffect(() => {
      setLoading(true);
      // 重置所有分页状态
      setFirstId(10);
      setLastId(20);
      setHasMore(true);
    
      const fetchData = async () => {
        const data = categoryId 
          ? await client.fetch(searchQuery(categoryId)) 
          : await client.fetch(feedQuery);
        setItems(data);
        setPages(data.slice(0, 10));
        setLoading(false);
        if (data.length <= 10) setHasMore(false);
      };
    
      fetchData();
    }, [categoryId]);
    

4. 优化InfiniteScroll配置

确保dataLength正确反映已加载条目数,同时调整endMessage的位置(它应该是InfiniteScroll的props,而非Spinner的属性):

<InfiniteScroll
  dataLength={pages?.length}
  next={fetchNextPage}
  hasMore={hasMore}
  loader={<Spinner message="Searching for items..." />}
  endMessage={
    <p className="align-center font-extrabold">End of list.</p>
  }
>
  {/* 内容 */}
</InfiniteScroll>

修改后的完整代码

import React, { useState, useEffect } from "react";
import { useParams } from "react-router-dom";
import { client } from "../client";
import MasonryLayout from "./MasonryLayout";
import Spinner from "./Spinner";
import { feedQuery, searchQuery } from "../utils/data";
import InfiniteScroll from "react-infinite-scroll-component";

const Feed = () => {
  const [loading, setLoading] = useState(false);
  const { categoryId } = useParams();
  const [items, setItems] = useState(null);
  const [pages, setPages] = useState([]);
  const [firstId, setFirstId] = useState(10);
  const [lastId, setLastId] = useState(20);
  const [hasMore, setHasMore] = useState(true);

  useEffect(() => {
    setLoading(true);
    setFirstId(10);
    setLastId(20);
    setHasMore(true);

    const fetchData = async () => {
      const data = categoryId 
        ? await client.fetch(searchQuery(categoryId)) 
        : await client.fetch(feedQuery);
      setItems(data);
      setPages(data.slice(0, 10));
      setLoading(false);
      if (data.length <= 10) setHasMore(false);
    };

    fetchData();
  }, [categoryId]);

  const fetchNextPage = () => {
    const result = items.slice(firstId, lastId);
    setPages(prevPages => [...prevPages, ...result]);
    if (result.length === 0 || result.length < 10) {
      setHasMore(false);
    }
    setFirstId(prev => prev + 10);
    setLastId(prev => prev + 10);
  };

  if (loading) return <Spinner message="Searching for items...!" />;
  if (!pages?.length) return <h2>No results available.</h2>;

  return (
    <InfiniteScroll
      dataLength={pages?.length}
      next={fetchNextPage}
      hasMore={hasMore}
      loader={<Spinner message="Searching for items..." />}
      endMessage={
        <p className="align-center font-extrabold">End of list.</p>
      }
    >
      <div className="min-h-screen">
        <div className="mt-4 mb-4 w-full rounded overflow-hidden shadow-lg bg-slate-50 pl-2 pr-2 pt-4 pb-4">
          <p>Some information about this … </p>
        </div>
        {pages && <MasonryLayout items={pages} />}
      </div>
    </InfiniteScroll>
  );
};
export default Feed;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 06:05:11