排序指南

示例

想要直接跳到实现部分吗?请查看以下示例:

API

排序 API

排序指南

TanStack Table 为您可能遇到的几乎所有排序用例都提供了解决方案。本指南将引导您了解可用于自定义内置客户端排序功能的各种选项,以及如何选择退出客户端排序而使用手动服务器端排序。

排序状态

排序状态定义为一个对象数组,其形状如下:

tsx
type ColumnSort = {
  id: string
  desc: boolean
}
type SortingState = ColumnSort[]
type ColumnSort = {
  id: string
  desc: boolean
}
type SortingState = ColumnSort[]

由于排序状态是一个数组,因此可以同时按多个列进行排序。有关多列排序自定义的更多信息,请参阅下文

访问排序状态

您可以像访问任何其他状态一样,使用 table.getState() API 直接从表格实例访问排序状态。

tsx
const table = useReactTable({
  columns,
  data,
  //...
})

console.log(table.getState().sorting) // 从表格实例访问排序状态
const table = useReactTable({
  columns,
  data,
  //...
})

console.log(table.getState().sorting) // 从表格实例访问排序状态

但是,如果您需要在初始化表格之前访问排序状态,则可以像下面这样“控制”排序状态。

受控排序状态

如果您需要轻松访问排序状态,可以使用 state.sortingonSortingChange 表格选项在您自己的状态管理中控制/管理排序状态。

tsx
const [sorting, setSorting] = useState<SortingState>([]) // 可以在此处设置初始排序状态
//...
// 使用排序状态从服务器获取数据或执行其他操作...
//...
const table = useReactTable({
  columns,
  data,
  //...
  state: {
    sorting,
  },
  onSortingChange: setSorting,
})
const [sorting, setSorting] = useState<SortingState>([]) // 可以在此处设置初始排序状态
//...
// 使用排序状态从服务器获取数据或执行其他操作...
//...
const table = useReactTable({
  columns,
  data,
  //...
  state: {
    sorting,
  },
  onSortingChange: setSorting,
})

初始排序状态

如果您不需要在自己的状态管理或作用域中控制排序状态,但仍想设置初始排序状态,则可以使用 initialState 表格选项而不是 state

jsx
const table = useReactTable({
  columns,
  data,
  //...
  initialState: {
    sorting: [
      {
        id: 'name',
        desc: true, // 默认按名称降序排序
      },
    ],
  },
})
const table = useReactTable({
  columns,
  data,
  //...
  initialState: {
    sorting: [
      {
        id: 'name',
        desc: true, // 默认按名称降序排序
      },
    ],
  },
})

注意:不要同时使用 initialState.sortingstate.sorting,因为 state.sorting 中初始化的状态将覆盖 initialState.sorting

客户端排序与服务器端排序

是否应使用客户端排序或服务器端排序完全取决于您是否也使用客户端或服务器端分页或筛选。保持一致,因为将客户端排序与服务器端分页或筛选一起使用只会对当前加载的数据进行排序,而不是整个数据集。

手动服务器端排序

如果您计划在后端逻辑中使用自己的服务器端排序,则无需提供排序后的行模型。但是,如果您已提供排序行模型,但想禁用它,则可以使用 manualSorting 表格选项。

jsx
const [sorting, setSorting] = useState<SortingState>([])
//...
const table = useReactTable({
  columns,
  data,
  getCoreRowModel: getCoreRowModel(),
  //getSortedRowModel: getSortedRowModel(), //手动排序不需要
  manualSorting: true, //使用预排序的行模型而不是排序后的行模型
  state: {
    sorting,
  },
  onSortingChange: setSorting,
})
const [sorting, setSorting] = useState<SortingState>([])
//...
const table = useReactTable({
  columns,
  data,
  getCoreRowModel: getCoreRowModel(),
  //getSortedRowModel: getSortedRowModel(), //手动排序不需要
  manualSorting: true, //使用预排序的行模型而不是排序后的行模型
  state: {
    sorting,
  },
  onSortingChange: setSorting,
})

注意:当 manualSorting 设置为 true 时,表格将假定您提供的数据已排序,并且不会对其应用任何排序。

客户端排序

要实现客户端排序,首先必须向表格提供排序行模型。您可以从 TanStack Table 导入 getSortedRowModel 函数,它将用于将您的行转换为排序后的行。

jsx
import { useReactTable } from '@tanstack/react-table'
//...
const table = useReactTable({
  columns,
  data,
  getCoreRowModel: getCoreRowModel(),
  getSortedRowModel: getSortedRowModel(), //提供排序行模型
})
import { useReactTable } from '@tanstack/react-table'
//...
const table = useReactTable({
  columns,
  data,
  getCoreRowModel: getCoreRowModel(),
  getSortedRowModel: getSortedRowModel(), //提供排序行模型
})

Sorting Fns

所有列的默认排序函数都是根据列的数据类型推断出来的。但是,为特定列定义要使用的确切排序函数可能很有用,尤其是在您的任何数据可为空或不是标准数据类型的情况下。

您可以使用 sortingFn 列选项按列确定自定义排序函数。

默认情况下,有 6 个内置排序函数可供选择:

  • alphanumeric - 按混合字母数字值排序,不区分大小写。速度较慢,但如果字符串包含需要自然排序的数字,则更准确。
  • alphanumericCaseSensitive - 按混合字母数字值排序,区分大小写。速度较慢,但如果字符串包含需要自然排序的数字,则更准确。
  • text - 按文本/字符串值排序,不区分大小写。速度较快,但如果字符串包含需要自然排序的数字,则不太准确。
  • textCaseSensitive - 按文本/字符串值排序,区分大小写。速度较快,但如果字符串包含需要自然排序的数字,则不太准确。
  • datetime - 按时间排序,如果值为 Date 对象,则使用此函数。
  • basic - 使用基本/标准 a > b ? 1 : a < b ? -1 : 0 比较进行排序。这是最快的排序函数,但可能不是最准确的。

您还可以将自定义排序函数定义为 sortingFn 列选项,或使用 sortingFns 表格选项将其定义为全局排序函数。

自定义排序函数

sortingFns 表格选项或 sortingFn 列选项中定义自定义排序函数时,它应具有以下签名:

tsx
//可选地使用 SortingFn 推断参数类型
const myCustomSortingFn: SortingFn<TData> = (rowA: Row<TData>, rowB: Row<TData>, columnId: string) => {
  return //-1、0 或 1 - 使用 rowA.original 和 rowB.original 访问任何行数据
}
//可选地使用 SortingFn 推断参数类型
const myCustomSortingFn: SortingFn<TData> = (rowA: Row<TData>, rowB: Row<TData>, columnId: string) => {
  return //-1、0 或 1 - 使用 rowA.original 和 rowB.original 访问任何行数据
}

注意:比较函数不需要考虑列是按降序还是升序排列。行模型将处理该逻辑。sortingFn 函数只需要提供一致的比较。

每个排序函数接收 2 行和一个列 ID,并期望使用列 ID 比较这两行以按升序返回 -101。这是一个速查表:

返回值升序
-1a < b
0a === b
1a > b
jsx
const columns = [
  {
    header: () => 'Name',
    accessorKey: 'name',
    sortingFn: 'alphanumeric', // 按名称使用内置排序函数
  },
  {
    header: () => 'Age',
    accessorKey: 'age',
    sortingFn: 'myCustomSortingFn', // 使用自定义全局排序函数
  },
  {
    header: () => 'Birthday',
    accessorKey: 'birthday',
    sortingFn: 'datetime', // 建议用于日期列
  },
  {
    header: () => 'Profile',
    accessorKey: 'profile',
    // 直接使用自定义排序函数
    sortingFn: (rowA, rowB, columnId) => {
      return rowA.original.someProperty - rowB.original.someProperty
    },
  }
]
//...
const table = useReactTable({
  columns,
  data,
  getCoreRowModel: getCoreRowModel(),
  getSortedRowModel: getSortedRowModel(),
  sortingFns: { //添加自定义排序函数
    myCustomSortingFn: (rowA, rowB, columnId) => {
      return rowA.original[columnId] > rowB.original[columnId] ? 1 : rowA.original[columnId] < rowB.original[columnId] ? -1 : 0
    },
  },
})
const columns = [
  {
    header: () => 'Name',
    accessorKey: 'name',
    sortingFn: 'alphanumeric', // 按名称使用内置排序函数
  },
  {
    header: () => 'Age',
    accessorKey: 'age',
    sortingFn: 'myCustomSortingFn', // 使用自定义全局排序函数
  },
  {
    header: () => 'Birthday',
    accessorKey: 'birthday',
    sortingFn: 'datetime', // 建议用于日期列
  },
  {
    header: () => 'Profile',
    accessorKey: 'profile',
    // 直接使用自定义排序函数
    sortingFn: (rowA, rowB, columnId) => {
      return rowA.original.someProperty - rowB.original.someProperty
    },
  }
]
//...
const table = useReactTable({
  columns,
  data,
  getCoreRowModel: getCoreRowModel(),
  getSortedRowModel: getSortedRowModel(),
  sortingFns: { //添加自定义排序函数
    myCustomSortingFn: (rowA, rowB, columnId) => {
      return rowA.original[columnId] > rowB.original[columnId] ? 1 : rowA.original[columnId] < rowB.original[columnId] ? -1 : 0
    },
  },
})

自定义排序

有许多表格和列选项可用于进一步自定义排序 UX 和行为。

禁用排序

您可以使用 enableSorting 列选项或表格选项禁用特定列或整个表格的排序。

jsx
const columns = [
  {
    header: () => 'ID',
    accessorKey: 'id',
    enableSorting: false, // 禁用此列的排序
  },
  {
    header: () => 'Name',
    accessorKey: 'name',
  },
  //...
]
//...
const table = useReactTable({
  columns,
  data,
  enableSorting: false, // 禁用整个表格的排序
})
const columns = [
  {
    header: () => 'ID',
    accessorKey: 'id',
    enableSorting: false, // 禁用此列的排序
  },
  {
    header: () => 'Name',
    accessorKey: 'name',
  },
  //...
]
//...
const table = useReactTable({
  columns,
  data,
  enableSorting: false, // 禁用整个表格的排序
})

排序方向

默认情况下,使用 toggleSorting API 循环列的排序时,字符串列的第一个排序方向是升序,数字列的第一个排序方向是降序。您可以使用 sortDescFirst 列选项或表格选项更改此行为。

jsx
const columns = [
  {
    header: () => 'Name',
    accessorKey: 'name',
    sortDescFirst: true, //首先按名称降序排序(字符串列默认为升序)
  },
  {
    header: () => 'Age',
    accessorKey: 'age',
    sortDescFirst: false, //首先按年龄升序排序(数字列默认为降序)
  },
  //...
]
//...
const table = useReactTable({
  columns,
  data,
  sortDescFirst: true, //首先按所有列降序排序(字符串列默认为升序,数字列默认为降序)
})
const columns = [
  {
    header: () => 'Name',
    accessorKey: 'name',
    sortDescFirst: true, //首先按名称降序排序(字符串列默认为升序)
  },
  {
    header: () => 'Age',
    accessorKey: 'age',
    sortDescFirst: false, //首先按年龄升序排序(数字列默认为降序)
  },
  //...
]
//...
const table = useReactTable({
  columns,
  data,
  sortDescFirst: true, //首先按所有列降序排序(字符串列默认为升序,数字列默认为降序)
})

注意:您可能希望在任何具有可为空值的列上显式设置 sortDescFirst 列选项。如果列包含可为空的值,表格可能无法正确确定该列是数字还是字符串。

反转排序

反转排序与更改默认排序方向不同。如果列的 invertSorting 列选项为 true,则“降序/升序”排序状态仍将正常循环,但行的实际排序将被反转。这对于具有反向最佳/最差等级的值(其中较小的数字更好,例如排名(第一、第二、第三)或类似高尔夫的评分)非常有用。

jsx
const columns = [
  {
    header: () => 'Rank',
    accessorKey: 'rank',
    invertSorting: true, // 反转此列的排序。即使应用了“降序”排序,也是第一 -> 第二 -> 第三 -> ...
  },
  //...
]
const columns = [
  {
    header: () => 'Rank',
    accessorKey: 'rank',
    invertSorting: true, // 反转此列的排序。即使应用了“降序”排序,也是第一 -> 第二 -> 第三 -> ...
  },
  //...
]

排序未定义值

任何未定义的值都将根据 sortUndefined 列选项或表格选项排序到列表的开头或末尾。您可以针对特定用例自定义此行为。

如果未指定,sortUndefined 的默认值为 1,未定义的值将按较低优先级(降序)排序,如果升序,未定义将出现在列表的末尾。

  • 'first' - 未定义的值将被推到列表��开头
  • 'last' - 未定义的值将被推到列表的末尾
  • false - 未定义的值将被视为并列,需要按下一列筛选器或原始索引(以适用者为准)进行排序
  • -1 - 未定义的值将按较高优先级(升序)排序(如果升序,未定义将出现在列表的开头)
  • 1 - 未定义的值将按较低优先级(降序)排序(如果升序,未定义将出现在列表的末尾)

注意:'first''last' 选项是 v8.16.0 中的新增选项

jsx
const columns = [
  {
    header: () => 'Rank',
    accessorKey: 'rank',
    sortUndefined: -1, // 'first' | 'last' | 1 | -1 | false
  },
]
const columns = [
  {
    header: () => 'Rank',
    accessorKey: 'rank',
    sortUndefined: -1, // 'first' | 'last' | 1 | -1 | false
  },
]

排序移除

默认情况下,在循环列的排序状态时移除排序的功能是启用的。您可以使用 enableSortingRemoval 表格选项禁用此行为。如果您想确保至少有一列始终处于排序状态,则此行为很有用。

使用 getToggleSortingHandlertoggleSorting API 时的默认行为是像这样循环排序状态:

'none' -> 'desc' -> 'asc' -> 'none' -> 'desc' -> 'asc' -> ...

如果禁用排序移除,则行为将如下所示:

'none' -> 'desc' -> 'asc' -> 'desc' -> 'asc' -> ...

一旦对列进行排序并且 enableSortingRemovalfalse,切换该列的排序将永远不会移除排序。但是,如果用户按另一列排序并且不是多列排序事件,则将从上一列中移除排序并仅应用于新列。

如果要确保至少有一列始终处于排序状态,请将 enableSortingRemoval 设置为 false

jsx
const table = useReactTable({
  columns,
  data,
  enableSortingRemoval: false, // 禁用移除列排序的功能(始终为 none -> asc -> desc -> asc)
})
const table = useReactTable({
  columns,
  data,
  enableSortingRemoval: false, // 禁用移除列排序的功能(始终为 none -> asc -> desc -> asc)
})

多列排序

默认情况下,如果使用 column.getToggleSortingHandler API,则启用同时按多列排序。如果用户在单击列标题时按住 Shift 键,表格将按该列以及已排序的列进行排序。如果使用 column.toggleSorting API,则必须手动传递是否使用多列排序。(column.toggleSorting(desc, multi))。

禁用多列排序

您可以使用 enableMultiSort 列选项或表格选项禁用特定列或整个表格的多列排序。禁用特定列的多列排序将用新列的排序替换所有现有排序。

jsx
const columns = [
  {
    header: () => 'Created At',
    accessorKey: 'createdAt',
    enableMultiSort: false, // 如果按此列排序,则始终仅按此列排序
  },
  //...
]
//...
const table = useReactTable({
  columns,
  data,
  enableMultiSort: false, // 禁用整个表格的多列排序
})
const columns = [
  {
    header: () => 'Created At',
    accessorKey: 'createdAt',
    enableMultiSort: false, // 如果按此列排序,则始终仅按此列排序
  },
  //...
]
//...
const table = useReactTable({
  columns,
  data,
  enableMultiSort: false, // 禁用整个表格的多列排序
})
自定义多列排序触发器

默认情况下,使用 Shift 键触发多列排序。您可以使用 isMultiSortEvent 表格选项更改此行为。您甚至可以通过从自定义函数返回 true 来指定所有排序事件都应触发多列排序。

jsx
const table = useReactTable({
  columns,
  data,
  isMultiSortEvent: (e) => true, // 普通单击触发多列排序
  //或
  isMultiSortEvent: (e) => e.ctrlKey || e.shiftKey, // 也使用 `Ctrl` 键触发多列排序
})
const table = useReactTable({
  columns,
  data,
  isMultiSortEvent: (e) => true, // 普通单击触发多列排序
  //或
  isMultiSortEvent: (e) => e.ctrlKey || e.shiftKey, // 也使用 `Ctrl` 键触发多列排序
})
多列排序限制

默认情况下,可以同时排序的列数没有限制。您可以使用 maxMultiSortColCount 表格选项设置限制。

jsx
const table = useReactTable({
  columns,
  data,
  maxMultiSortColCount: 3, // 一次只允许排序 3 列
})
const table = useReactTable({
  columns,
  data,
  maxMultiSortColCount: 3, // 一次只允许排序 3 列
})
多列排序移除

默认情况下,移除多列排序的功能是启用的。您可以使用 enableMultiRemove 表格选项禁用此行为。

jsx
const table = useReactTable({
  columns,
  data,
  enableMultiRemove: false, // 禁用移除多列排序的功能
})
const table = useReactTable({
  columns,
  data,
  enableMultiRemove: false, // 禁用移除多列排序的功能
})

排序 API

有许多与排序相关的 API 可用于连接到您的 UI 或其他逻辑。以下是所有排序 API 及其一些用例的列表。

  • table.setSorting - 直接设置排序状态。

  • table.resetSorting - 将排序状态重置为初始状态或清除它。

  • column.getCanSort - 用于启用/禁用列的排序 UI。

  • column.getIsSorted - 用于显示列的可视排序指示器。

  • column.getToggleSortingHandler - 用于连接列的排序 UI。添加到排序箭头(图标按钮)、菜单项或只是整个列表头单元格。此处理程序将使用正确的参数调用 column.toggleSorting

  • column.toggleSorting - 用于连接列的排序 UI。如果使用而不是 column.getToggleSortingHandler,则必须手动传递是否使用多列排序。(column.toggleSorting(desc, multi)

  • column.clearSorting - 用于特定列的“清除排序”按钮或菜单项。

  • column.getNextSortingOrder - 用于显示列接下来将按哪个方向排序。(工具提示/菜单项/aria-label 或其他内容中的 asc/desc/clear)

  • column.getFirstSortDir - 用于显示列首先将按哪个方向排序。(工具提示/菜单项/aria-label 或其他内容中的 asc/desc)

  • column.getAutoSortDir - 确定列的第一个排序方向是升序还是降序。

  • column.getAutoSortingFn - 用于在未指定时查找列的默认排序函数。

  • column.getSortingFn - 返回用于列的确切排序函数。

  • column.getCanMultiSort - 用于启用/禁用列的多列排序 UI。

  • column.getSortIndex - 用于在多列排序场景中显示列排序顺序的徽章或指示器。即,它是否是要排序的第一列、第二列、第三列等。