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

