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

React+SWRInfinite无限滚动首次请求重复触发问题求助

问题排查与解决方案

前端usePagination钩子核心问题

1. getKey函数未缓存,触发useSWRInfinite重复初始化

usePagination中getKey直接定义在钩子内部,每次钩子重渲染都会生成新的getKey实例。useSWRInfinite会将getKey作为依赖,当函数引用变化时,会重置整个无限滚动请求状态,重新发起第一页请求。

修复方案:用useCallback包裹getKey,依赖url保证函数引用稳定:

import { useCallback } from 'react';
import useSWRInfinite from 'swr/infinite';

export const usePagination = <T>(url:string)=>{
    const getKey = useCallback((pageIndex:number, previousPageData: T[])=>{
        const currentPage = pageIndex + 1;
        if(previousPageData && !previousPageData.length) return null;
        return `${url}?_page=${currentPage}&_limit=40`;
    }, [url]);

    const {data, size, setSize, error, mutate} = useSWRInfinite(getKey, fetcher);
    // 修正拼写错误:paginatedDatam → paginatedData,isRechedEnd → isReachedEnd,mute → mutate
    const paginatedData: T[] = data?.flat() as T[];
    const dataArrLen = data ? data.length -1 : 0;
    const innerDataArr = data ? data[dataArrLen] as T[]: [];
    const isReachedEnd = data && innerDataArr.length < 40;
    const loadingMore = data && typeof data[size-1] === 'undefined';
    
    return  {
        paginatedData, isReachedEnd, loadingMore, size, setSize, error, mutate
    };
}

2. 拼写错误导致状态异常

代码中存在多处拼写错误,会导致组件无法正确读取状态,引发滚动逻辑混乱:

  • paginatedDatam → paginatedData
  • isRechedEnd → isReachedEnd
  • mute → mutate(useSWRInfinite的正确返回值为mutate)

后端分页逻辑错误

1. getAllItems接口分页计算逻辑错误

当前后端代码错误修改limit值,导致分页范围完全混乱:

limit = (page-1) * limit < 40 ? 40 : (page-1)*limit

例如page=2、limit=40时,计算后limit变为40,与第一页请求范围完全一致。

修复方案:修正为标准分页逻辑,计算offset(跳过的条数)而非修改limit:

const getAllItems = async(request) => {
    let { _page, _limit} = request.query;
    if(_page && _limit)
    {
        const itemsDao = new ItemDao();
        const page = parseInt(_page);
        const limit = parseInt(_limit);
        const offset = (page - 1) * limit;
        const allItems = await itemsDao.getAllItems(offset, limit);
        return new JsonResult(200, allItems);
    }
    return new JsonResult(200, {});
}

2. ItemDao数据读取逻辑错误

  • 循环提前return:return items写在for循环内部,导致循环仅执行一次就返回,永远只能拿到最多1条数据
  • Schema校验语法错误:ItemsSchema.safeParse(itemsJson2Array[i].success)应为ItemsSchema.safeParse(itemsJson2Array[i]).success,错误访问了success属性
  • 分页范围计算错误:原逻辑用limit代替偏移量+条数的组合,导致分页逻辑混乱

修复方案:修正ItemDao的getAllItems方法:

export class ItemDao extends Database{
    public async getAllItems(offset: number, limit: number){
        const generatedData = JSON.parse(JSON.stringify(randomItems));
        const itemsJson2Array = Object.values(generatedData);
        const items = [];
        // 计算安全的结束索引,避免超出数组长度
        const endIndex = Math.min(offset + limit, itemsJson2Array.length);
        
        for (let i = offset; i < endIndex ; i++){
            const item = itemsJson2Array[i];
            if(ItemsSchema.safeParse(item).success){
                items.push(item);
            }
        }
        return items;
    }
}

无限滚动组件优化

绑定loadingMore状态到InfiniteScroll的loading属性,避免加载过程中重复触发next:

const {paginatedData, setSize, isReachedEnd, loadingMore} = useGetAllItems()

return (
    <>
        <InfiniteScroll 
            next={()=>setSize(_size=> _size+1)} 
            hasMore={!isReachedEnd}
            loading={loadingMore}
        >
            <ItemsCard items={paginatedData} />
        </InfiniteScroll>
    </>
)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 07:25:09