Lzh on GitHub

示例

想跳过实现部分吗?请查看这些示例:

  • 排序
  • 筛选器

排序指南

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

排序状态

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

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

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

访问排序状态

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

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

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

受控排序状态

如果你需要方便地访问排序状态,你可以在自己的状态管理中通过 state.sortingonSortingChange 表格选项来控制/管理排序状态。

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

初始排序状态

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

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

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

客户端与服务器端排序

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

手动服务器端排序

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

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 函数,它将用于将你的行转换为已排序的行。

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

排序函数

所有列的默认排序函数都是从列的数据类型推断出来的。但是,为特定列定义你想要使用的确切排序函数会很有用,特别是当你的任何数据是可空或不是标准数据类型时。

你可以使用 sortingFn 列选项为每列确定自定义排序函数。

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

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

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

自定义排序函数

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

// 可以选择使用 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
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;
    },
  },
});

自定义排序

有很多表格和列选项可以用来进一步自定义排序的用户体验和行为。

禁用排序

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

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

排序方向

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

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

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

反转排序

反转排序与更改默认排序方向不同。如果列的 invertSorting 列选项为 true,那么“desc/asc”排序状态仍将正常循环,但行的实际排序将反转。这对于具有反向最佳/最差刻度(其中数字越低越好)的值很有用,例如排名(第 1、第 2、第 3)或高尔夫式得分。

const columns = [
  {
    header: () => 'Rank',
    accessorKey: 'rank',
    invertSorting: true, // 反转此列的排序。即使应用了“desc”排序,也是 1st -> 2nd -> 3rd -> ...
  },
  //...
];

排序未定义值

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

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

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

注意'first''last' 选项是 v8.16.0 中的新功能。

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

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

多重排序

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

禁用多重排序

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

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

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

const table = useReactTable({
  columns,
  data,
  isMultiSortEvent: (e) => true, // 正常点击触发多重排序
  //或者
  isMultiSortEvent: (e) => e.ctrlKey || e.shiftKey, // 也使用 `Ctrl` 键触发多重排序
});
多重排序限制

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

const table = useReactTable({
  columns,
  data,
  maxMultiSortColCount: 3, // 只允许同时对 3 列进行排序
});
多重排序移除

默认情况下,可以移除多重排序。你可以使用 enableMultiRemove 表格选项禁用此行为。

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 - 在多重排序场景中用于显示列排序顺序的徽章或指示器。即它是第一、第二、第三等排序的列。