框架
版本
企业版

列过滤指南

示例

想直接看实现?可以参考以下示例

API

列过滤 API

列过滤指南

过滤分为两种:列过滤和全局过滤。

本指南将重点关注列过滤,即应用于单个列的访问器值的过滤器。

TanStack Table 支持客户端过滤和手动服务器端过滤。本指南将介绍如何实现和自定义这两种过滤方式,并帮助您决定哪种最适合您的用例。

客户端与服务器端过滤

如果您拥有大量数据集,可能不希望将所有数据加载到客户端浏览器中进行过滤。在这种情况下,您很可能需要实现服务器端过滤、排序、分页等。

然而,正如在 分页指南 中所讨论的,许多开发人员低估了在不影响性能的情况下,可以在客户端加载的行数。TanStack Table 的示例通常经过测试,能够以不错的性能处理多达 100,000 行甚至更多行的客户端过滤、排序、分页和分组。这并不一定意味着您的应用程序能够处理这么多行,但如果您的表格最多只有几千行,您或许可以利用 TanStack Table 提供的客户端过滤、排序、分页和分组功能。

TanStack Table 可以以良好的性能处理数千行的客户端数据。不要在没有深思熟虑之前就排除客户端过滤、分页、排序等功能。

每种用例都不同,具体取决于表的复杂性、有多少列、每块数据的大小等。需要注意的主要瓶颈是

  1. 您的服务器能否在合理的时间内(和成本)查询所有数据?
  2. 获取的总数据量是多少?(如果没有太多列,这可能不会像您想的那么糟糕。)
  3. 如果一次性加载所有数据,客户端浏览器是否会占用过多内存?

如果您不确定,可以随时从客户端过滤和分页开始,然后在未来随着数据量的增长切换到服务器端策略。

手动服务器端过滤

如果您已决定需要实现服务器端过滤而不是使用内置的客户端过滤,则可以按以下方式进行。

手动服务器端过滤不需要 getFilteredRowModel 表格选项。相反,您传递给表格的 data 应该已经过过滤。但是,如果您传递了 getFilteredRowModel 表格选项,可以通过将 manualFiltering 选项设置为 true 来告诉表格跳过它。

jsx
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 函数,或者创建自己的函数。

jsx
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 可以修改和交互过滤状态,并检索列过滤状态。

列过滤状态定义为具有以下形状的对象数组

ts
interface ColumnFilter {
  id: string
  value: unknown
}
type ColumnFiltersState = ColumnFilter[]
interface ColumnFilter {
  id: string
  value: unknown
}
type ColumnFiltersState = ColumnFilter[]

由于列过滤状态是对象数组,您可以同时应用多个列过滤器。

访问列过滤状态

您可以使用 table.getState() API 从表格实例访问列过滤状态,就像访问其他表格状态一样。

jsx
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.columnFiltersonColumnFiltersChange 表格选项,在自己的状态管理中控制/管理列过滤状态。

tsx
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

jsx
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.columnFiltersstate.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 表格选项中定义自定义过滤函数时,它应该具有以下签名

ts
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

每个过滤函数都接收

  • 要过滤的行
  • 用于检索行值的 columnId
  • 过滤值

并应返回 true 如果该行应包含在过滤后的行中,否则返回 false 如果应将其删除。

jsx
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 时将过滤值从表格状态中删除。

tsx
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

jsx
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 将导致过滤从叶子节点向上进行,这意味着只要其子行或孙行被包含,父行就会被包含。

jsx
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

jsx
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

有许多列和表格 API 可供您与列过滤状态进行交互,并连接到您的 UI 组件。以下是可用 API 及其最常见用例的列表

  • table.setColumnFilters - 使用新状态覆盖整个列过滤状态

  • table.resetColumnFilters - 适用于“全部清除/重置过滤器”按钮

  • column.getFilterValue - 用于获取输入的默认初始过滤值,甚至直接为过滤输入提供过滤值

  • column.setFilterValue - 用于将过滤输入连接到它们的 onChangeonBlur 事件处理程序

  • column.getCanFilter - 用于禁用/启用过滤输入

  • column.getIsFiltered - 用于显示列当前正在过滤的视觉指示器

  • column.getFilterIndex - 用于显示当前过滤应用的顺序

  • column.getAutoFilterFn -

  • column.getFilterFn - 用于显示当前使用的过滤模式或函数

我们的合作伙伴
Code Rabbit
AG Grid
订阅 Bytes

您的每周 JavaScript 资讯。每周一免费发送给超过 10 万开发者。

Bytes

无垃圾邮件。您可以随时取消订阅。

订阅 Bytes

您的每周 JavaScript 资讯。每周一免费发送给超过 10 万开发者。

Bytes

无垃圾邮件。您可以随时取消订阅。