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

React Query无限滚动结合React Table v8实现单表格无限数据加载问题求助

解决React Query无限滚动 + React Table v8单表格展示问题

你现在的核心问题是把每个分页的数据集都渲染成了独立的Table组件,所以页面上会出现多个表格。我们只需要把所有分页的数据合并成一个完整的数据集,传给单个Table组件,再搭配滚动触发下一页加载的逻辑就可以解决问题。下面是分步修改方案:

第一步:合并所有分页数据,渲染单个Table

在父组件中,不要遍历pages渲染多个Table,而是把所有分页里的content合并成一个一维数组,然后传给单个Table:

import { useMemo } from 'react';

// 合并所有分页的 shipment 数据
const allShipments = useMemo(() => {
  return shipments?.pages.flatMap(page => page.content) || [];
}, [shipments?.pages]);

// 只渲染一个 Table 组件,传入合并后的完整数据
return (
  <div>
    <Table allShipments={allShipments} />
    {/* 后续添加无限滚动触发逻辑 */}
    {shipments.isFetchingNextPage && <div>加载中...</div>}
    {!shipments.hasNextPage && <div>没有更多数据了</div>}
  </div>
);

第二步:修改Table组件的Props与数据处理

原来的Table组件接收单个分页的group,现在调整为接收合并后的完整数组,同时更新对应的类型和数据解析逻辑:

import { useMemo, useState } from 'react';
import { useTableInstance, getCoreRowModel } from '@tanstack/react-table';

// 更新Props类型,接收合并后的所有数据
type TableProps = {
  allShipments: Shipment[];
};

// 列定义保持不变,这里省略重复代码
const table = createTable().setRowType<ShipmentRow>();
const defaultColumns = [/* 你的列定义代码 */];

const Table = ({ allShipments }: TableProps) => {
  // 解析所有数据,而不是单个分页的数据
  const parsedShipments = useMemo(
    () => allShipments.map((shipment: Shipment) => ({
      id: shipment.id,
      orderDate: dayjs(shipment.createDate).format("DD MMMM"),
      merchantName: shipment.merchant ? shipment.merchant.name : shipment.senderAddress.name,
      senderTown: shipment.senderAddress.town,
      receiverTown: shipment.receiverAddress.town,
      receivingDriver: shipment.receivingDriver ? `${shipment.receivingDriver.name} ${shipment.receivingDriver.surname}` : "Atanmadı",
      deliveryDriver: shipment.deliveryDriver ? `${shipment.deliveryDriver.name} ${shipment.deliveryDriver.surname}` : "Atanmadı",
      totalDeciOct: shipment.totalDeciOct,
      totalPartnerPrice: shipment.totalPartnerPrice,
      abbreviation: shipment.merchant ? shipment.merchant.abbreviation : shipment.partnerCompany.abbreviation,
      deliveryAttempts: shipment.deliveryAttempts,
      rendezvousDeliveryDate: shipment.rendezvousDeliveryDate,
      status: shipment.status,
    })) ?? [],
    [allShipments]
  );

  const [columns] = useState<typeof defaultColumns>(() => [...defaultColumns]);
  const instance = useTableInstance(table, {
    data: parsedShipments,
    columns,
    getCoreRowModel: getCoreRowModel(),
  });

  // 表格渲染结构保持不变,现在会展示所有合并后的数据
  return (
    <S.Table>
      <S.HeadTbody>
        {instance.getHeaderGroups().map((headerGroup) => (
          <tr key={headerGroup.id}>
            {headerGroup.headers.map((header) => (
              <S.HeadTh key={header.id} colSpan={header.colSpan}>
                {header.isPlaceholder ? null : header.renderHeader()}
              </S.HeadTh>
            ))}
          </tr>
        ))}
      </S.HeadTbody>
      <S.DataTbody>
        {instance.getRowModel().rows.map((row) => (
          <S.StyledTr key={row.id}>
            {row.getVisibleCells().map((cell) => (
              <S.StyledTh key={cell.id}>{cell.renderCell()}</S.StyledTh>
            ))}
          </S.StyledTr>
        ))}
      </S.DataTbody>
    </S.Table>
  );
};

export default Table;

第三步:实现无限滚动触发下一页加载

我们需要监听滚动位置,当用户滚动到页面底部时,触发React Query的fetchNextPage方法。这里提供两种常用实现方式:

方式1:使用原生Intersection Observer API

在父组件中添加一个触发元素,用Intersection Observer监听它是否进入视口:

import { useRef, useEffect } from 'react';

const loadMoreRef = useRef<HTMLDivElement>(null);

useEffect(() => {
  const observer = new IntersectionObserver(
    (entries) => {
      const entry = entries[0];
      // 当元素进入视口、当前未加载下一页、还有更多数据时,触发加载
      if (entry.isIntersecting && !shipments.isFetchingNextPage && shipments.hasNextPage) {
        shipments.fetchNextPage();
      }
    },
    { threshold: 0.1 }
  );

  const currentRef = loadMoreRef.current;
  if (currentRef) observer.observe(currentRef);

  return () => {
    if (currentRef) observer.unobserve(currentRef);
  };
}, [shipments.hasNextPage, shipments.isFetchingNextPage, shipments.fetchNextPage]);

// 在Table下方添加触发元素
return (
  <div>
    <Table allShipments={allShipments} />
    <div ref={loadMoreRef} style={{ height: '20px', margin: '20px 0' }}>
      {shipments.isFetchingNextPage && <span>加载中...</span>}
    </div>
    {!shipments.hasNextPage && <div>没有更多数据了</div>}
  </div>
);

方式2:使用第三方库简化开发

如果不想手写监听逻辑,可以用react-infinite-scroll-component库:

首先安装依赖:

npm install react-infinite-scroll-component

然后在父组件中使用:

import InfiniteScroll from 'react-infinite-scroll-component';

return (
  <InfiniteScroll
    dataLength={allShipments.length}
    next={shipments.fetchNextPage}
    hasMore={shipments.hasNextPage}
    loader={<div>加载中...</div>}
    endMessage={<div>没有更多数据了</div>}
  >
    <Table allShipments={allShipments} />
  </InfiniteScroll>
);

关键注意事项

  • 确保你的useInfiniteQuery配置了正确的getNextPageParam,这样React Query才能正确判断是否还有下一页数据。
  • 用useMemo包裹合并后的数据和解析后的数据,避免不必要的组件重渲染。
  • 新数据加载后,React Table会自动更新,因为parsedShipments依赖allShipments,而allShipments会随着shipments.pages更新。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 01:32:31