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
相关产品推荐
相关产品推荐

