React Infinite Queries是否支持offset与limit模式的无限滚动?
React Query Infinite Queries 适配 Offset + Limit 模式方案
当然支持!React Query 的 Infinite Queries 完全可以适配你这种基于 limit 和 offset 的分页 API,只需要自定义分页参数的计算逻辑就行,我之前在项目里也这么实现过,结合 react-virtual 做无限滚动非常顺畅。
核心配置要点
要让 Infinite Queries 兼容 offset 模式,关键是配置 getNextPageParam(如果需要上拉加载上一页,还可以配置 getPreviousPageParam),同时调整 queryFn 来接收 offset 参数。
1. 编写 Query 函数
你的 queryFn 需要接收 pageParam 参数,这个参数就是当前的 offset 值(初始可以设为 0)。调用 API 时带上 limit 和 offset,并返回数据和元信息供后续分页判断使用:
const fetchItems = async ({ pageParam = 0 }) => { const response = await fetch(`/api/items?limit=100&offset=${pageParam}`); const data = await response.json(); return { items: data.items, meta: data.meta, // 包含 limit, offset, total 字段 }; };
2. 配置 useInfiniteQuery
在 useInfiniteQuery 中,通过 getNextPageParam 计算下一页的 offset,同时判断是否还有更多数据:
import { useInfiniteQuery } from '@tanstack/react-query'; const { data, fetchNextPage, hasNextPage, isFetchingNextPage } = useInfiniteQuery({ queryKey: ['infiniteItems'], queryFn: fetchItems, // 计算下一页的 offset,并判断是否还有更多数据 getNextPageParam: (lastPage) => { const nextOffset = lastPage.meta.offset + lastPage.meta.limit; // 如果下一页的 offset 超过总数据量,返回 undefined 表示没有更多数据 return nextOffset < lastPage.meta.total ? nextOffset : undefined; }, });
结合 react-virtual 实现无限滚动
react-virtual 需要知道总数据条数来计算滚动区域,我们可以从元信息的 total 字段获取。然后把 Infinite Queries 返回的所有页面数据扁平化为一个数组,供虚拟列表渲染:
import { useVirtual } from '@tanstack/react-virtual'; import { useEffect, useRef } from 'react'; // 扁平化所有页面的数据 const allItems = data?.pages.flatMap(page => page.items) || []; // 总数据条数 const totalItems = data?.pages[0]?.meta.total || 0; const parentRef = useRef(null); const rowVirtualizer = useVirtual({ size: totalItems, parentRef, estimateSize: () => 50, // 根据你的列表项实际高度调整 }); // 监听滚动,当滚动接近底部时触发下一页加载 useEffect(() => { const handleScroll = () => { if (parentRef.current) { const { scrollTop, clientHeight, scrollHeight } = parentRef.current; // 距离底部还有 200px 时触发加载(可根据需求调整阈值) if (scrollTop + clientHeight >= scrollHeight - 200 && hasNextPage && !isFetchingNextPage) { fetchNextPage(); } } }; const element = parentRef.current; element?.addEventListener('scroll', handleScroll); return () => element?.removeEventListener('scroll', handleScroll); }, [hasNextPage, isFetchingNextPage, fetchNextPage]);
关键注意事项
- 有效判断下一页:一定要基于
total和下一页的offset来判断,避免触发无效的 API 请求 - 初始 offset 对齐:确保
pageParam的默认值和你的 API 起始 offset 一致(通常是 0) - 数据扁平化:react-virtual 需要连续的数据数组,所以要把
pages中的每一页数据合并成一个整体
这样配置后,Infinite Queries 就会自动管理 offset 的递增,结合 react-virtual 的虚拟滚动,就能实现高效流畅的无限滚动效果啦!
内容的提问来源于stack exchange,提问作者Pubudu Jayasanka
相关产品推荐
相关产品推荐

