想直接看实现?可以参考以下示例
过滤分为两种:列过滤和全局过滤。
本指南将重点关注列过滤,即应用于单个列的访问器值的过滤器。
TanStack Table 支持客户端过滤和手动服务器端过滤。本指南将介绍如何实现和自定义这两种过滤方式,并帮助您决定哪种最适合您的用例。
如果您拥有大量数据集,可能不希望将所有数据加载到客户端浏览器中进行过滤。在这种情况下,您很可能需要实现服务器端过滤、排序、分页等。
然而,正如在 分页指南 中所讨论的,许多开发人员低估了在不影响性能的情况下,可以在客户端加载的行数。TanStack Table 的示例通常经过测试,能够以不错的性能处理多达 100,000 行甚至更多行的客户端过滤、排序、分页和分组。这并不一定意味着您的应用程序能够处理这么多行,但如果您的表格最多只有几千行,您或许可以利用 TanStack Table 提供的客户端过滤、排序、分页和分组功能。
TanStack Table 可以以良好的性能处理数千行的客户端数据。不要在没有深思熟虑之前就排除客户端过滤、分页、排序等功能。
每种用例都不同,具体取决于表的复杂性、有多少列、每块数据的大小等。需要注意的主要瓶颈是
如果您不确定,可以随时从客户端过滤和分页开始,然后在未来随着数据量的增长切换到服务器端策略。
如果您已决定需要实现服务器端过滤而不是使用内置的客户端过滤,则可以按以下方式进行。
手动服务器端过滤不需要 getFilteredRowModel 表格选项。相反,您传递给表格的 data 应该已经过过滤。但是,如果您传递了 getFilteredRowModel 表格选项,可以通过将 manualFiltering 选项设置为 true 来告诉表格跳过它。
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
// getFilteredRowModel: getFilteredRowModel(), // not needed for manual server-side filtering
manualFiltering: true,
})
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
// getFilteredRowModel: getFilteredRowModel(), // not needed for manual server-side filtering
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(), // needed for client-side filtering
})
import { useReactTable, getFilteredRowModel } from '@tanstack/react-table'
//...
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
getFilteredRowModel: getFilteredRowModel(), // needed for client-side filtering
})
无论您使用客户端过滤还是服务器端过滤,都可以利用 TanStack Table 提供的内置列过滤状态管理。有许多表格和列 API 可以修改和交互过滤状态,并检索列过滤状态。
列过滤状态定义为具有以下形状的对象数组
interface ColumnFilter {
id: string
value: unknown
}
type ColumnFiltersState = ColumnFilter[]
interface ColumnFilter {
id: string
value: unknown
}
type ColumnFiltersState = ColumnFilter[]
由于列过滤状态是对象数组,您可以同时应用多个列过滤器。
您可以使用 table.getState() API 从表格实例访问列过滤状态,就像访问其他表格状态一样。
const table = useReactTable({
columns,
data,
//...
})
console.log(table.getState().columnFilters) // access the column filters state from the table instance
const table = useReactTable({
columns,
data,
//...
})
console.log(table.getState().columnFilters) // access the column filters state from the table instance
但是,如果您需要在表格初始化之前访问列过滤状态,可以像下面一样“控制”列过滤状态。
如果您需要轻松访问列过滤状态,可以使用 state.columnFilters 和 onColumnFiltersChange 表格选项,在自己的状态管理中控制/管理列过滤状态。
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]) // can set initial column filter state here
//...
const table = useReactTable({
columns,
data,
//...
state: {
columnFilters,
},
onColumnFiltersChange: setColumnFilters,
})
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]) // can set initial column filter state here
//...
const table = useReactTable({
columns,
data,
//...
state: {
columnFilters,
},
onColumnFiltersChange: setColumnFilters,
})
如果您不需要在自己的状态管理或作用域中控制列过滤状态,但仍想设置初始列过滤状态,可以使用 initialState 表格选项而不是 state。
const table = useReactTable({
columns,
data,
//...
initialState: {
columnFilters: [
{
id: 'name',
value: 'John', // filter the name column by 'John' by default
},
],
},
})
const table = useReactTable({
columns,
data,
//...
initialState: {
columnFilters: [
{
id: 'name',
value: 'John', // filter the name column by 'John' by default
},
],
},
})
注意: 请勿同时使用 initialState.columnFilters 和 state.columnFilters,因为 state.columnFilters 中的初始化状态将覆盖 initialState.columnFilters。
每个列都可以拥有自己独特的过滤逻辑。您可以从 TanStack Table 提供的任何过滤函数中选择,或者创建自己的函数。
默认情况下,有 10 种内置过滤函数可供选择
您还可以通过 filterFn 列选项或使用 filterFns 表格选项作为全局过滤函数来定义自己的自定义过滤函数。
注意: 这些过滤函数仅在客户端过滤期间运行。
在 filterFn 列选项或 filterFns 表格选项中定义自定义过滤函数时,它应该具有以下签名
const myCustomFilterFn: FilterFn = (row: Row, columnId: string, filterValue: any, addMeta: (meta: any) => void) => boolean
const myCustomFilterFn: FilterFn = (row: Row, columnId: string, filterValue: any, addMeta: (meta: any) => void) => boolean
每个过滤函数都接收
并应返回 true 如果该行应包含在过滤后的行中,否则返回 false 如果应将其删除。
const columns = [
{
header: () => 'Name',
accessorKey: 'name',
filterFn: 'includesString', // use built-in filter function
},
{
header: () => 'Age',
accessorKey: 'age',
filterFn: 'inNumberRange',
},
{
header: () => 'Birthday',
accessorKey: 'birthday',
filterFn: 'myCustomFilterFn', // use custom global filter function
},
{
header: () => 'Profile',
accessorKey: 'profile',
// use custom filter function directly
filterFn: (row, columnId, filterValue) => {
return // true or false based on your custom logic
},
}
]
//...
const table = useReactTable({
columns,
data,
getCoreRowModel: getCoreRowModel(),
getFilteredRowModel: getFilteredRowModel(),
filterFns: { //add a custom sorting function
myCustomFilterFn: (row, columnId, filterValue) => { //defined inline here
return // true or false based on your custom logic
},
startsWith: startsWithFilterFn, // defined elsewhere
},
})
const columns = [
{
header: () => 'Name',
accessorKey: 'name',
filterFn: 'includesString', // use built-in filter function
},
{
header: () => 'Age',
accessorKey: 'age',
filterFn: 'inNumberRange',
},
{
header: () => 'Birthday',
accessorKey: 'birthday',
filterFn: 'myCustomFilterFn', // use custom global filter function
},
{
header: () => 'Profile',
accessorKey: 'profile',
// use custom filter function directly
filterFn: (row, columnId, filterValue) => {
return // true or false based on your custom logic
},
}
]
//...
const table = useReactTable({
columns,
data,
getCoreRowModel: getCoreRowModel(),
getFilteredRowModel: getFilteredRowModel(),
filterFns: { //add a custom sorting function
myCustomFilterFn: (row, columnId, filterValue) => { //defined inline here
return // true or false based on your custom logic
},
startsWith: startsWithFilterFn, // defined elsewhere
},
})
您可以向过滤函数附加一些其他属性来自定义其行为
filterFn.resolveFilterValue - 任何给定的 filterFn 上的这个可选“挂钩”方法允许过滤函数在将过滤值传递给过滤函数之前对其进行转换/清理/格式化。
filterFn.autoRemove - 任何给定的 filterFn 上的这个可选“挂钩”方法会接收一个过滤值,并期望返回 true 如果该过滤值应从过滤状态中删除。例如,某些布尔型过滤器可能希望在过滤值设置为 false 时将过滤值从表格状态中删除。
const startsWithFilterFn = <TData extends MRT_RowData>(
row: Row<TData>,
columnId: string,
filterValue: number | string, //resolveFilterValue will transform this to a string
) =>
row
.getValue<number | string>(columnId)
.toString()
.toLowerCase()
.trim()
.startsWith(filterValue); // toString, toLowerCase, and trim the filter value in `resolveFilterValue`
// remove the filter value from filter state if it is falsy (empty string in this case)
startsWithFilterFn.autoRemove = (val: any) => !val;
// transform/sanitize/format the filter value before it is passed to the filter function
startsWithFilterFn.resolveFilterValue = (val: any) => val.toString().toLowerCase().trim();
const startsWithFilterFn = <TData extends MRT_RowData>(
row: Row<TData>,
columnId: string,
filterValue: number | string, //resolveFilterValue will transform this to a string
) =>
row
.getValue<number | string>(columnId)
.toString()
.toLowerCase()
.trim()
.startsWith(filterValue); // toString, toLowerCase, and trim the filter value in `resolveFilterValue`
// remove the filter value from filter state if it is falsy (empty string in this case)
startsWithFilterFn.autoRemove = (val: any) => !val;
// transform/sanitize/format the filter value before it is passed to the filter function
startsWithFilterFn.resolveFilterValue = (val: any) => val.toString().toLowerCase().trim();
有许多表格和列选项可供您进一步自定义列过滤行为。
默认情况下,所有列都启用了列过滤。您可以使用 enableColumnFilters 表格选项或 enableColumnFilter 列选项来禁用所有列或特定列的列过滤。您还可以通过将 enableFilters 表格选项设置为 false 来关闭列过滤和全局过滤。
禁用列的列过滤将导致该列的 column.getCanFilter API 返回 false。
const columns = [
{
header: () => 'Id',
accessorKey: 'id',
enableColumnFilter: false, // disable column filtering for this column
},
//...
]
//...
const table = useReactTable({
columns,
data,
enableColumnFilters: false, // disable column filtering for all columns
})
const columns = [
{
header: () => 'Id',
accessorKey: 'id',
enableColumnFilter: false, // disable column filtering for this column
},
//...
]
//...
const table = useReactTable({
columns,
data,
enableColumnFilters: false, // disable column filtering for all columns
})
有几个额外的表格选项可以自定义列过滤在使用展开、分组和聚合等功能时的行为。
默认情况下,过滤是从父行向下进行的,因此如果父行被过滤掉,其所有子行也将被过滤掉。根据您的用例,如果您只希望用户搜索顶级行而不搜索子行,这可能是理想的行为。这也是性能最优的选择。
但是,如果您希望允许过滤和搜索子行,而不管父行是否被过滤掉,您可以将 filterFromLeafRows 表格选项设置为 true。将此选项设置为 true 将导致过滤从叶子节点向上进行,这意味着只要其子行或孙行被包含,父行就会被包含。
const table = useReactTable({
columns,
data,
getCoreRowModel: getCoreRowModel(),
getFilteredRowModel: getFilteredRowModel(),
getExpandedRowModel: getExpandedRowModel(),
filterFromLeafRows: true, // filter and search through sub-rows
})
const table = useReactTable({
columns,
data,
getCoreRowModel: getCoreRowModel(),
getFilteredRowModel: getFilteredRowModel(),
getExpandedRowModel: getExpandedRowModel(),
filterFromLeafRows: true, // filter and search through sub-rows
})
默认情况下,过滤是对树中的所有行进行的,无论它们是根级别的父行还是父行的子叶子节点。将 maxLeafRowFilterDepth 表格选项设置为 0 将导致过滤仅应用于根级别的父行,所有子行都保持未过滤状态。类似地,将此选项设置为 1 将导致过滤仅应用于深度为 1 的子叶子节点,依此类推。
如果您想在父行通过过滤时保留其子行不被过滤掉,请使用 maxLeafRowFilterDepth: 0。
const table = useReactTable({
columns,
data,
getCoreRowModel: getCoreRowModel(),
getFilteredRowModel: getFilteredRowModel(),
getExpandedRowModel: getExpandedRowModel(),
maxLeafRowFilterDepth: 0, // only filter root level parent rows out
})
const table = useReactTable({
columns,
data,
getCoreRowModel: getCoreRowModel(),
getFilteredRowModel: getFilteredRowModel(),
getExpandedRowModel: getExpandedRowModel(),
maxLeafRowFilterDepth: 0, // only filter root level parent rows out
})
有许多列和表格 API 可供您与列过滤状态进行交互,并连接到您的 UI 组件。以下是可用 API 及其最常见用例的列表
table.setColumnFilters - 使用新状态覆盖整个列过滤状态
table.resetColumnFilters - 适用于“全部清除/重置过滤器”按钮
column.getFilterValue - 用于获取输入的默认初始过滤值,甚至直接为过滤输入提供过滤值
column.setFilterValue - 用于将过滤输入连接到它们的 onChange 或 onBlur 事件处理程序
column.getCanFilter - 用于禁用/启用过滤输入
column.getIsFiltered - 用于显示列当前正在过滤的视觉指示器
column.getFilterIndex - 用于显示当前过滤应用的顺序
column.getAutoFilterFn -
column.getFilterFn - 用于显示当前使用的过滤模式或函数
您的每周 JavaScript 资讯。每周一免费发送给超过 10 万开发者。