框架
版本
企业版

分页指南

示例

想直接看实现?可以参考以下示例

API

分页 API

分页指南

TanStack Table 对客户端和服务器端分页都提供了出色的支持。本指南将引导您了解实现表格分页的不同方法。

客户端分页

使用客户端分页意味着您获取的 data 将包含表格的所有行,并且表格实例将在前端处理分页逻辑。

是否应该使用客户端分页?

使用 TanStack Table 实现分页通常最简单的方法是客户端分页,但这对于非常大的数据集可能不实用。

然而,许多人低估了客户端可以处理的数据量。如果您的表格最多只有几千行,客户端分页仍然是一个可行的选择。TanStack Table 的设计能够处理数万行的数据,并在分页、过滤、排序和分组方面提供良好的性能。官方的 分页示例 加载了 100,000 行数据,并且仍然运行良好,尽管列数不多。

每种用例都不同,具体取决于表的复杂性、有多少列、每块数据的大小等。需要注意的主要瓶颈是

  1. 您的服务器能否在合理的时间内(和成本)查询所有数据?
  2. 获取的总数据量是多少?(如果没有太多列,这可能不会像您想的那么糟糕。)
  3. 如果一次性加载所有数据,客户端浏览器是否会占用过多内存?

如果您不确定,可以随时从客户端分页开始,并在未来随着数据量的增长切换到服务器端分页。

是否应该使用虚拟化代替?

或者,您可以不分页数据,而是将大型数据集的所有行渲染到同一页面,但仅使用浏览器的资源来渲染视口中可见的行。这种策略通常被称为“虚拟化”或“窗口化”。TanStack 提供了一个名为 TanStack Virtual 的虚拟化库,它可以与 TanStack Table 很好地配合使用。虚拟化和分页的 UI/UX 各有其优缺点,因此请选择最适合您用例的方案。

分页行模型

如果您想利用 TanStack Table 内置的客户端分页功能,首先需要传入分页行模型。

jsx
import { useReactTable, getCoreRowModel, getPaginationRowModel } from '@tanstack/react-table';
//...
const table = useReactTable({
  columns,
  data,
  getCoreRowModel: getCoreRowModel(),
  getPaginationRowModel: getPaginationRowModel(), //load client-side pagination code
});
import { useReactTable, getCoreRowModel, getPaginationRowModel } from '@tanstack/react-table';
//...
const table = useReactTable({
  columns,
  data,
  getCoreRowModel: getCoreRowModel(),
  getPaginationRowModel: getPaginationRowModel(), //load client-side pagination code
});

手动服务器端分页

如果您决定需要使用服务器端分页,以下是实现方法。

服务器端分页不需要分页行模型,但如果您已经在共享组件中为其他需要它的表格提供了分页行模型,您仍然可以通过将 manualPagination 选项设置为 true 来关闭客户端分页。将 manualPagination 选项设置为 true 会告诉表格实例在底层使用 table.getPrePaginationRowModel 行模型,并假定您传入的 data 已经过分页。

页数和行数

表格实例无法得知后端总共有多少行/页,除非您告诉它。提供 rowCountpageCount 表格选项,以告知表格实例总共有多少页。如果您提供 rowCount,表格实例将根据 rowCountpageSize 在内部计算 pageCount。否则,您可以直接提供您已有的 pageCount。如果您不知道页数,可以将 pageCount 设置为 -1,在这种情况下,getCanNextPagegetCanPreviousPage 行模型函数将始终返回 true

jsx
import { useReactTable, getCoreRowModel, getPaginationRowModel } from '@tanstack/react-table';
//...
const table = useReactTable({
  columns,
  data,
  getCoreRowModel: getCoreRowModel(),
  // getPaginationRowModel: getPaginationRowModel(), //not needed for server-side pagination
  manualPagination: true, //turn off client-side pagination
  rowCount: dataQuery.data?.rowCount, //pass in the total row count so the table knows how many pages there are (pageCount calculated internally if not provided)
  // pageCount: dataQuery.data?.pageCount, //alternatively directly pass in pageCount instead of rowCount
});
import { useReactTable, getCoreRowModel, getPaginationRowModel } from '@tanstack/react-table';
//...
const table = useReactTable({
  columns,
  data,
  getCoreRowModel: getCoreRowModel(),
  // getPaginationRowModel: getPaginationRowModel(), //not needed for server-side pagination
  manualPagination: true, //turn off client-side pagination
  rowCount: dataQuery.data?.rowCount, //pass in the total row count so the table knows how many pages there are (pageCount calculated internally if not provided)
  // pageCount: dataQuery.data?.pageCount, //alternatively directly pass in pageCount instead of rowCount
});

注意:将 manualPagination 选项设置为 true 会使表格实例假定您传入的 data 已经过分页。

分页状态

无论您使用的是客户端分页还是手动服务器端分页,都可以使用内置的 pagination 状态和 API。

pagination 状态是一个包含以下属性的对象:

  • pageIndex: 当前页码(从零开始)。
  • pageSize: 当前页面大小。

您可以像管理表格实例中的任何其他状态一样管理 pagination 状态。

jsx
import { useReactTable, getCoreRowModel, getPaginationRowModel } from '@tanstack/react-table';
//...
const [pagination, setPagination] = useState({
  pageIndex: 0, //initial page index
  pageSize: 10, //default page size
});

const table = useReactTable({
  columns,
  data,
  getCoreRowModel: getCoreRowModel(),
  getPaginationRowModel: getPaginationRowModel(),
  onPaginationChange: setPagination, //update the pagination state when internal APIs mutate the pagination state
  state: {
    //...
    pagination,
  },
});
import { useReactTable, getCoreRowModel, getPaginationRowModel } from '@tanstack/react-table';
//...
const [pagination, setPagination] = useState({
  pageIndex: 0, //initial page index
  pageSize: 10, //default page size
});

const table = useReactTable({
  columns,
  data,
  getCoreRowModel: getCoreRowModel(),
  getPaginationRowModel: getPaginationRowModel(),
  onPaginationChange: setPagination, //update the pagination state when internal APIs mutate the pagination state
  state: {
    //...
    pagination,
  },
});

或者,如果您不需要在自己的作用域内管理 pagination 状态,但需要为 pageIndexpageSize 设置不同的初始值,可以使用 initialState 选项。

jsx
const table = useReactTable({
  columns,
  data,
  getCoreRowModel: getCoreRowModel(),
  getPaginationRowModel: getPaginationRowModel(),
  initialState: {
    pagination: {
      pageIndex: 2, //custom initial page index
      pageSize: 25, //custom default page size
    },
  },
});
const table = useReactTable({
  columns,
  data,
  getCoreRowModel: getCoreRowModel(),
  getPaginationRowModel: getPaginationRowModel(),
  initialState: {
    pagination: {
      pageIndex: 2, //custom initial page index
      pageSize: 25, //custom default page size
    },
  },
});

注意:请勿将 pagination 状态同时传递给 stateinitialState 选项。state 将覆盖 initialState。只需使用其中一个。

分页选项

除了 manualPaginationpageCountrowCount 选项(这些选项对于手动服务器端分页很有用,并在 上面 进行了讨论),还有一个表格选项值得了解。

自动重置页码

默认情况下,当发生分页状态改变时(例如,data 更新、筛选条件改变、分组改变等),pageIndex 会重置为 0。当 manualPagination 为 true 时,此行为会自动禁用,但可以通过显式为 autoResetPageIndex 表格选项赋值布尔值来覆盖。

jsx
const table = useReactTable({
  columns,
  data,
  getCoreRowModel: getCoreRowModel(),
  getPaginationRowModel: getPaginationRowModel(),
  autoResetPageIndex: false, //turn off auto reset of pageIndex
});
const table = useReactTable({
  columns,
  data,
  getCoreRowModel: getCoreRowModel(),
  getPaginationRowModel: getPaginationRowModel(),
  autoResetPageIndex: false, //turn off auto reset of pageIndex
});

但请注意,如果您关闭 autoResetPageIndex,您可能需要添加一些逻辑来手动重置 pageIndex,以避免显示空页。

分页 API

有几个分页表格实例 API 对于连接您的分页 UI 组件非常有用。

分页按钮 API

  • getCanPreviousPage: 在第一页时禁用“上一页”按钮很有用。
  • getCanNextPage: 当没有更多页面时禁用“下一页”按钮很有用。
  • previousPage: 跳转到上一页很有用。(按钮点击处理程序)
  • nextPage: 跳转到下一页很有用。(按钮点击处理程序)
  • firstPage: 跳转到第一页很有用。(按钮点击处理程序)
  • lastPage: 跳转到最后一页很有用。(按钮点击处理程序)
  • setPageIndex: 对于“转到页面”输入框很有用。
  • resetPageIndex: 重置表格状态到原始页码很有用。
  • setPageSize: 对于“页面大小”输入框/选择框很有用。
  • resetPageSize: 重置表格状态到原始页面大小很有用。
  • setPagination: 一次性设置所有分页状态很有用。
  • resetPagination: 重置表格状态到原始分页状态很有用。

注意:其中一些 API 在 v8.13.0 中是新增的。

jsx
<Button
  onClick={() => table.firstPage()}
  disabled={!table.getCanPreviousPage()}
>
  {'<<'}
</Button>
<Button
  onClick={() => table.previousPage()}
  disabled={!table.getCanPreviousPage()}
>
  {'<'}
</Button>
<Button
  onClick={() => table.nextPage()}
  disabled={!table.getCanNextPage()}
>
  {'>'}
</Button>
<Button
  onClick={() => table.lastPage()}
  disabled={!table.getCanNextPage()}
>
  {'>>'}
</Button>
<select
  value={table.getState().pagination.pageSize}
  onChange={e => {
    table.setPageSize(Number(e.target.value))
  }}
>
  {[10, 20, 30, 40, 50].map(pageSize => (
    <option key={pageSize} value={pageSize}>
      {pageSize}
    </option>
  ))}
</select>
<Button
  onClick={() => table.firstPage()}
  disabled={!table.getCanPreviousPage()}
>
  {'<<'}
</Button>
<Button
  onClick={() => table.previousPage()}
  disabled={!table.getCanPreviousPage()}
>
  {'<'}
</Button>
<Button
  onClick={() => table.nextPage()}
  disabled={!table.getCanNextPage()}
>
  {'>'}
</Button>
<Button
  onClick={() => table.lastPage()}
  disabled={!table.getCanNextPage()}
>
  {'>>'}
</Button>
<select
  value={table.getState().pagination.pageSize}
  onChange={e => {
    table.setPageSize(Number(e.target.value))
  }}
>
  {[10, 20, 30, 40, 50].map(pageSize => (
    <option key={pageSize} value={pageSize}>
      {pageSize}
    </option>
  ))}
</select>

分页信息 API

  • getPageCount: 显示总页数很有用。
  • getRowCount: 显示总行数很有用。
我们的合作伙伴
Code Rabbit
AG Grid
订阅 Bytes

您的每周 JavaScript 资讯。每周一免费发送给超过 10 万开发者。

Bytes

无垃圾邮件。您可以随时取消订阅。

订阅 Bytes

您的每周 JavaScript 资讯。每周一免费发送给超过 10 万开发者。

Bytes

无垃圾邮件。您可以随时取消订阅。