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

React无限滚动组件加载初始数据后无法加载后续数据

问题排查与修复方案

以下是针对你的react-infinite-scroll组件持续显示"Loading..."无法加载下一页的核心问题排查与修复步骤:


1. 修复后端Cursor分页逻辑(核心问题)

你的后端分页存在排序字段与游标不匹配的错误:使用name排序,但游标基于id,这会导致分页逻辑混乱,出现重复数据或无法正确获取下一页的情况,最终让hasNextPage一直为true,组件持续触发加载。

修改后端代码:

const limit = 10;

getAllItemsInfinite: protectedProcedure
  .input(
    z.object({
      cursor: z.string().nullish(),
      householdId: z.string(),
    })
  )
  .query(async ({ ctx, input }) => {
    const { cursor, householdId } = input;
    // 调整排序与游标一致,使用id作为排序和游标字段
    const items = await ctx.prisma.item.findMany({
      cursor: cursor ? { id: cursor } : undefined,
      take: limit + 1,
      orderBy: {
        id: "asc", // 改为按id排序,与游标字段匹配
      },
      where: {
        householdId,
      },
    });

    // 替换错误的forEach异步遍历,改用Promise.all等待所有更新完成
    await Promise.all(items.map(async (item) => {
      if (item.expirationDate !== null) {
        const totalDays = calculateDaysUntilExpiry(item.expirationDate);

        await ctx.prisma.item.update({
          where: { id: item.id },
          data: {
            daysUntilExpiry: totalDays,
          },
        });

        if (totalDays < 0 && item.expired === false) {
          await ctx.prisma.item.update({
            where: { id: item.id },
            data: {
              expired: true,
            },
          });
        }
      }
    }));

    let nextCursor: typeof cursor | undefined = undefined;
    if (items.length > limit) {
      const nextItem = items.pop();
      if (nextItem) nextCursor = nextItem.id;
    }
    return {
      items,
      nextCursor,
    };
  }),

2. 修正前端InfiniteScroll的参数计算

当前dataLength使用原始数据长度,但实际渲染的是过滤后的结果,会导致滚动触发逻辑判断错误;同时补充请求状态判断,避免重复触发加载。

修改前端组件代码:

// 先提取过滤后的数组,避免重复计算
const filteredItems = getAllItemsInfinite.isSuccess 
  ? getAllItemsInfinite.data?.pages
      .flatMap(page => page.items)
      .filter(item => {
        if (debouncedValue === "") return true;
        const lowerQuery = debouncedValue.toLowerCase();
        return item.name.toLowerCase().includes(lowerQuery) 
          || item.brand?.toLowerCase().includes(lowerQuery);
      })
  : [];

// 渲染InfiniteScroll组件
<InfiniteScroll
  dataLength={filteredItems.length} // 使用过滤后的实际渲染长度
  next={getAllItemsInfinite.fetchNextPage}
  hasMore={!!getAllItemsInfinite.hasNextPage && !getAllItemsInfinite.isFetchingNextPage} // 避免重复请求
  loader={<h4 style={{ textAlign: "center", marginTop: "1rem" }}>Loading...</h4>}
  endMessage={
    filteredItems.length > 0 && !getAllItemsInfinite.hasNextPage && !getAllItemsInfinite.isLoading && (
      <p style={{ textAlign: "center" }}>
        <b>End of items.</b>
      </p>
    )
  }
>
  <div
    className={cn(
      "m-2 flex flex-wrap justify-center gap-1 3xl:mx-auto ",
      {
        "m-4 gap-4": showingItemCards,
      }
    )}
  >
    {filteredItems.map(item =>
      showingItemCards ? (
        <ItemCard key={item.id} {...item} />
      ) : (
        <Item key={item.id} {...item} />
      )
    )}
  </div>
</InfiniteScroll>

3. 样式排查补充

样式调整可能导致滚动容器高度计算异常,可通过浏览器开发者工具检查:

  • 确认InfiniteScroll的父容器未设置overflow: hidden且有正确的可滚动高度
  • 滚动到底部时,查看控制台是否触发了fetchNextPage(可添加console.log验证)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 02:27:03