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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 07:31:52