想要跳过实现?查看这些示例
TanStack Table 对客户端和服务器端分页都有出色的支持。本指南将引导您了解在表格中实现分页的不同方法。
使用客户端分页意味着您获取的 data 将包含表格的所有行,并且表格实例将在前端处理分页逻辑。
当使用 TanStack Table 时,客户端分页通常是实现分页的最简单方法,但对于非常大的数据集来说,它可能不实用。
然而,很多人低估了客户端可以处理多少数据。如果您的表格永远只有几千行或更少,客户端分页仍然是一个可行的选择。TanStack Table 旨在扩展到数万行,并在分页、筛选、排序和分组方面具有不错的性能。官方分页示例 加载了 100,000 行,并且仍然表现良好,尽管只有少数列。
每个用例都不同,并且将取决于表格的复杂性、您拥有的列数、每条数据的大小等等。需要注意的主要瓶颈是
如果您不确定,您可以始终从客户端分页开始,然后在将来随着数据的增长切换到服务端分页。
或者,除了分页数据之外,您可以在同一页面上渲染大型数据集的所有行,但仅使用浏览器的资源来渲染视口中可见的行。这种策略通常称为“虚拟化”或“窗口化”。TanStack 提供了一个名为 TanStack Virtual 的虚拟化库,它可以与 TanStack Table 很好地配合使用。虚拟化和分页的 UI/UX 都有各自的权衡,因此请查看哪一个最适合您的用例。
如果您想利用 TanStack Table 中内置的客户端分页,您首先需要传入分页行模型。
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 已经分页。
除非您告诉表格实例,否则它将无法知道您的后端总共有多少行/页。提供 rowCount 或 pageCount 表格选项,让表格实例知道总共有多少页。如果您提供 rowCount,表格实例将从 rowCount 和 pageSize 内部计算 pageCount。否则,如果您已经有了 pageCount,您可以直接提供它。如果您不知道页面计数,您可以为 pageCount 传入 -1,但在这种情况下,getCanNextPage 和 getCanPreviousPage 行模型函数将始终返回 true。
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 状态是一个对象,其中包含以下属性
您可以像管理表格实例中的任何其他状态一样管理 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,
},
});
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 状态,但需要为 pageIndex 和 pageSize 设置不同的初始值,则可以使用 initialState 选项。
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 状态同时传递给 state 和 initialState 选项。state 将覆盖 initialState。仅使用其中一个。
除了 manualPagination、pageCount 和 rowCount 选项(这些选项对于手动服务端分页很有用,并在上面讨论过)之外,还有一个其他表格选项值得理解。
默认情况下,当页面更改状态发生时,例如当 data 更新、筛选器更改、分组更改等时,pageIndex 会重置为 0。当 manualPagination 为 true 时,此行为会自动禁用,但可以通过显式为 autoResetPageIndex 表格选项分配布尔值来覆盖它。
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 可用于连接您的分页 UI 组件。
注意:其中一些 API 在 v8.13.0 中是新增的。
<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>
您每周的 JavaScript 新闻。每周一免费发送给超过 100,000 名开发者。