列过滤指南
示例
想跳过直接看实现?请查看这些示例:
列过滤指南
过滤有两种形式:列过滤 和 全局过滤。
本指南将重点介绍列过滤,它是一种应用于单个列的访问器值的过滤器。
TanStack Table 同时支持客户端和手动服务器端过滤。本指南将介绍如何实现和自定义这两种过滤,并帮助您决定哪种最适合您的用例。
客户端过滤 vs 服务器端过滤
如果您的数据集很大,您可能不想将所有数据加载到客户端浏览器中进行过滤。在这种情况下,您很可能需要实现服务器端过滤、排序、分页等。
然而,正如 分页指南 中也讨论的,许多开发者低估了在不影响性能的情况下可以在客户端加载的行数。TanStack Table 的示例经常测试处理多达 100,000 行或更多的数据,并在客户端过滤、排序、分页和分组方面表现出不错的性能。这并不意味着您的应用程序能够处理那么多行,但是如果您的表格最多只有几千行,您也许可以利用 TanStack Table 提供的客户端过滤、排序、分页和分组功能。
TanStack Table 可以很好地处理数千个客户端行。不要不经思考就排除客户端过滤、分页、排序等。
每个用例都不同,将取决于表格的复杂性、您有多少列、每条数据的大小等等。需要注意的主要瓶颈是:
- 您的服务器能否在合理的时间(和成本)内查询所有数据?
- 获取的总大小是多少?(如果您没有很多列,这可能不会像您想象的那么糟糕。)
- 如果所有数据都一次性加载,客户端浏览器是否会占用过多内存?
如果您不确定,您始终可以从客户端过滤和分页开始,然后随着数据增长在未来切换到服务器端策略。
手动服务器端过滤
如果您已决定需要实现服务器端过滤而不是使用内置的客户端过滤,以下是实现方法。
手动服务器端过滤不需要 getFilteredRowModel 表格选项。相反,您传递给表格的 data 应该已经过过滤。但是,如果您已经传递了 getFilteredRowModel 表格选项,您可以通过将 manualFiltering 选项设置为 true 来告诉表格跳过它。
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
// getFilteredRowModel: getFilteredRowModel(), // 手动服务器端过滤不需要
manualFiltering: true,
})
注意:使用手动过滤时,本指南其余部分讨论的许多选项将不起作用。当 manualFiltering 设置为 true 时,表格实例将不会对传递给它的行应用任何过滤逻辑。相反,它将假定这些行已经过过滤,并将按原样使用您传递给它的 data。
客户端过滤
如果您正在使用内置的客户端过滤功能,首先您需要将 getFilteredRowModel 函数传递给表格选项。每当表格需要过滤数据时,就会调用此函数。您可以从 TanStack Table 导入默认的 getFilteredRowModel 函数,或者创建自己的函数。
import { useReactTable, getFilteredRowModel } from '@tanstack/react-table'
//...
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
getFilteredRowModel: getFilteredRowModel(), // 客户端过滤需要
})
列过滤状态
无论您使用客户端还是服务器端过滤,您都可以利用 TanStack Table 提供的内置列过滤状态管理。有许多表格和列 API 可以改变和交互过滤状态以及检索列过滤状态。
列过滤状态被定义为一个对象数组,其形状如下:
interface ColumnFilter {
id: string
value: unknown
}
type ColumnFiltersState = ColumnFilter[]
由于列过滤状态是一个对象数组,因此您可以同时应用多个列过滤器。
访问列过滤状态
您可以使用 table.getState() API 从表格实例访问列过滤状态,就像访问任何其他表格状态一样。
const table = useReactTable({
columns,
data,
//...
})
console.log(table.getState().columnFilters) // 从表格实例访问列过滤器状态
但是,如果您需要在表格初始化之前访问列过滤状态,您可以像下面那样“控制”列过滤状态。
受控列过滤状态
如果您需要轻松访问列过滤状态,您可以使用 state.columnFilters 和 onColumnFiltersChange 表格选项在您自己的状态管理中控制/管理列过滤状态。
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]) // 可以在这里设置初始列过滤状态
//...
const table = useReactTable({
columns,
data,
//...
state: {
columnFilters,
},
onColumnFiltersChange: setColumnFilters,
})
初始列过滤状态
如果您不需要在自己的状态管理或范围内控制列过滤状态,但仍想设置初始列过滤状态,您可以使用 initialState 表格选项而不是 state。
const table = useReactTable({
columns,
data,
//...
initialState: {
columnFilters: [
{
id: 'name',
value: 'John', // 默认按 'John' 过滤名称列
},
],
},
})
注意:不要同时使用 initialState.columnFilters 和 state.columnFilters,因为 state.columnFilters 中初始化的状态会覆盖 initialState.columnFilters。
FilterFns
每列都可以有自己独特的过滤逻辑。您可以选择 TanStack Table 提供的任何过滤函数,或者创建自己的过滤函数。
默认情况下有 10 个内置的过滤函数可供选择:
includesString- 不区分大小写的字符串包含includesStringSensitive- 区分大小写的字符串包含equalsString- 不区分大小写的字符串相等equalsStringSensitive- 区分大小写的字符串相等arrIncludes- 数组内项包含arrIncludesAll- 数组包含所有项arrIncludesSome- 数组包含部分项equals- 对象/引用相等Object.is/===weakEquals- 弱对象/引用相等==inNumberRange- 数字范围包含
您还可以将自己的自定义过滤函数定义为 filterFn 列选项,或作为使用 filterFns 表格选项的全局过滤函数。
自定义过滤函数
注意:这些过滤函数只在客户端过滤期间运行。
当在 filterFn 列选项或 filterFns 表格选项中定义自定义过滤函数时,它应该具有以下签名:
const myCustomFilterFn: FilterFn = (row: Row, columnId: string, filterValue: any, addMeta: (meta: any) => void) => boolean
每个过滤函数接收:
- 要过滤的行
- 用于检索行值的
columnId - 过滤值
- 如果行应包含在过滤后的行中,则应返回
true,如果应删除,则返回false。
const columns = [
{
header: () => 'Name',
accessorKey: 'name',
filterFn: 'includesString', // 使用内置过滤函数
},
{
header: () => 'Age',
accessorKey: 'age',
filterFn: 'inNumberRange',
},
{
header: () => 'Birthday',
accessorKey: 'birthday',
filterFn: 'myCustomFilterFn', // 使用自定义全局过滤函数
},
{
header: () => 'Profile',
accessorKey: 'profile',
// 直接使用自定义过滤函数
filterFn: (row, columnId, filterValue) => {
return // 根据您的自定义逻辑返回 true 或 false
},
}]
//...
const table = useReactTable({
columns,
data,
getCoreRowModel: getCoreRowModel(),
getFilteredRowModel: getFilteredRowModel(),
filterFns: { // 添加自定义排序函数
myCustomFilterFn: (row, columnId, filterValue) => { // 在此处内联定义
return // 根据您的自定义逻辑返回 true 或 false
},
startsWith: startsWithFilterFn, // 在其他地方定义
},
})
自定义过滤函数行为
您可以向过滤函数附加一些其他属性以自定义其行为:
filterFn.resolveFilterValue- 任何给定filterFn上的这个可选的“悬挂”方法允许过滤函数在将过滤值传递给过滤函数之前对其进行转换/清理/格式化。filterFn.autoRemove- 任何给定filterFn上的这个可选的“悬挂”方法被传递一个过滤值,并期望返回true以便从过滤状态中移除该过滤值。例如,某些布尔型过滤器可能希望在过滤值设置为false时将其从表格状态中移除。
const startsWithFilterFn = <TData extends MRT_RowData>(
row: Row<TData>,
columnId: string,
filterValue: number | string, // resolveFilterValue 将其转换为字符串
) =>
row
.getValue<number | string>(columnId)
.toString()
.toLowerCase()
.trim()
.startsWith(filterValue); // 在 `resolveFilterValue` 中对过滤值进行 toString、toLowerCase 和 trim
// 如果过滤值是假值(本例中为空字符串),则从过滤状态中移除该过滤值
startsWithFilterFn.autoRemove = (val: any) => !val;
// 在将过滤值传递给过滤函数之前对其进行转换/清理/格式化
startsWithFilterFn.resolveFilterValue = (val: any) => val.toString().toLowerCase().trim();
自定义列过滤
您可以使用许多表格和列选项来进一步自定义列过滤行为。
禁用列过滤
默认情况下,所有列都启用了列过滤。您可以使用 enableColumnFilters 表格选项或 enableColumnFilter 列选项来禁用所有列或特定列的列过滤。您还可以通过将 enableFilters 表格选项设置为 false 来关闭列过滤和全局过滤。
禁用列的列过滤将导致该列的 column.getCanFilter API 返回 false。
const columns = [
{
header: () => 'Id',
accessorKey: 'id',
enableColumnFilter: false, // 禁用此列的列过滤
},
//...
]
//...
const table = useReactTable({
columns,
data,
enableColumnFilters: false, // 禁用所有列的列过滤
})
过滤子行(展开)
还有一些额外的表格选项可以自定义在使用展开、分组和聚合等功能时列过滤的行为。
从叶子行过滤
默认情况下,过滤是从父行向下进行的,因此如果一个父行被过滤掉,它的所有子行也将被过滤掉。根据您的用例,如果您只希望用户搜索顶级行而不是子行,这可能是期望的行为。这也是性能最高的选项。
但是,如果您希望允许子行被过滤和搜索,无论父行是否被过滤掉,您可以将 filterFromLeafRows 表格选项设置为 true。将此选项设置为 true 将导致过滤从叶子行向上进行,这意味着只要其子行或孙子行中有一个被包含,父行就会被包含。
const table = useReactTable({
columns,
data,
getCoreRowModel: getCoreRowModel(),
getFilteredRowModel: getFilteredRowModel(),
getExpandedRowModel: getExpandedRowModel(),
filterFromLeafRows: true, // 过滤和搜索子行
})
最大叶子行过滤深度
默认情况下,对树中的所有行进行过滤,无论它们是根级父行还是父行的子叶子行。将 maxLeafRowFilterDepth 表格选项设置为 0 将导致过滤只应用于根级父行,所有子行保持未过滤。类似地,将此选项设置为 1 将导致过滤只应用于深度为 1 的子叶子行,依此类推。
如果您希望在父行通过过滤时,保留父行的子行不被过滤掉,请使用 maxLeafRowFilterDepth: 0。
const table = useReactTable({
columns,
data,
getCoreRowModel: getCoreRowModel(),
getFilteredRowModel: getFilteredRowModel(),
getExpandedRowModel: getExpandedRowModel(),
maxLeafRowFilterDepth: 0, // 只过滤根级父行
})
列过滤 API
有许多列和表格 API 可用于与列过滤状态交互并连接到您的 UI 组件。以下是可用 API 及其最常见用例的列表:
table.setColumnFilters- 用新状态覆盖整个列过滤状态table.resetColumnFilters- 适用于“清除所有/重置过滤器”按钮column.getFilterValue- 适用于获取输入的默认初始过滤值,甚至直接向过滤输入提供过滤值column.setFilterValue- 适用于将过滤输入连接到其onChange或onBlur处理程序column.getCanFilter- 适用于禁用/启用过滤输入column.getIsFiltered- 适用于显示列当前正在被过滤的视觉指示器column.getFilterIndex- 适用于显示当前过滤器应用的顺序column.getAutoFilterFn-column.getFilterFn- 适用于显示当前正在使用的过滤模式或函数