ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

TanStack Table React 全局过滤(Global Filtering)完全指南:跨列搜索、模糊匹配与状态管理实战

2026/9/20 9:22:22 拓冰建站 浏览量
TanStack Table React 全局过滤(Global Filtering)完全指南:跨列搜索、模糊匹配与状态管理实战 TanStack Table React 全局过滤Global Filtering完全指南跨列搜索、模糊匹配与状态管理实战【免费下载链接】table Headless UI for building powerful tables datagrids for TS/JS - React-Table, Vue-Table, Solid-Table, Svelte-Table项目地址: https://gitcode.com/gh_mirrors/ta/table导读本文围绕 TanStack Table 官方 React 指南中的全局过滤Global Filtering主题展开系统讲解如何在tanstack/react-table中搭建一个搜索框过滤全表所有列的经典能力从特性注册、客户端/服务端两种过滤模型到 12 个内置过滤函数、自定义模糊过滤函数fuzzy filter、状态管理外部 atom 与受控 state 两种模式以及完整的过滤 API。读完本文你将能独立在 React 表格中实现高性能的跨列全局搜索并理解过滤行模型在底层是如何与列过滤、分页协作的。从示例开始两个可直接运行的 React 示例官方仓库为全局过滤提供了两个可直接运行的示例建议先运行它们观察效果再阅读源码Column Filters 示例展示了columnFilteringFeatureglobalFilteringFeature组合下的列过滤与全局过滤Fuzzy Search 示例演示了把模糊过滤函数用于全局过滤的典型场景含 100 万行压力测试按钮。这两个示例都位于examples/react/下采用 Vite TypeScript 结构可按仓库内各示例目录的package.json安装依赖后启动。全局过滤是什么与列过滤的区别TanStack Table 的过滤分为两种列过滤Column Filtering针对某个指定列单独过滤例如姓氏列只匹配特定值全局过滤Global Filtering一个过滤器同时应用于所有允许被过滤的列通常表现为表格上方的搜索输入框。全局过滤依赖列过滤特性因此在注册特性时columnFilteringFeature必须放在globalFilteringFeature之前import { useTable, tableFeatures, columnFilteringFeature, globalFilteringFeature, createFilteredRowModel, filterFn_includesString, } from tanstack/react-table const features tableFeatures({ columnFilteringFeature, globalFilteringFeature, filteredRowModel: createFilteredRowModel(), // if using client-side filtering // manualFiltering: true, // if using manual server-side filtering filterFns: { includesString: filterFn_includesString }, }) const table useTable({ features, columns, data, })[!NOTE] 上面的filterFns注册表只列出了本表用到的内置过滤函数。虽然直接展开整个内置注册表filterFns: { ...filterFns }也能工作但会把所有内置过滤函数打进你的打包产物。只注册实际用到的函数或者直接把函数传给globalFilterFn选项完全无需注册。从源码看globalFilteringFeatureglobalFilteringFeature.ts负责四件事注入globalFilter初始状态、提供默认表选项globalFilterFn: auto、onGlobalFilterChange、getColumnCanGlobalFilter判定、挂载列上的getCanGlobalFilterAPI、挂载表上的setGlobalFilter/resetGlobalFilter/getGlobalFilterFn/getGlobalAutoFilterFn四个 API。也就是说添加特性即启用相关 API正是源码中assignPrototypeAPIs与constructTableAPIs两个钩子完成的。客户端过滤与服务端过滤先做正确决策过滤应该与排序、分页作用于同一份数据集浏览器持有完整数据集时使用客户端过滤client-side filtering浏览器只持有一页或一个子集时使用服务端过滤server-side filtering除非仅过滤已加载的行是有意为之。完整的决策框架、性能因素与数据操作组合建议参见 Client-Side vs Server-Side Guide。一个重要的行为细节客户端过滤行模型在全局过滤输入变化时会触发页码自动重置钩子。是否重置取决于autoResetPageIndex、autoResetAll与manualPagination选项。如果过滤是手动的manual且行模型被省略或绕过全局过滤状态变化不会触发该钩子因此需要在过滤变化的事件处理器里手动重置服务端分页。这一逻辑在 createFilteredRowModel.ts 中可以看到行模型通过tableMemo将globalFilteratom 作为记忆依赖并在更新后调用table_autoResetPageIndex(table)。手动服务端全局过滤Manual Server-Side Global Filtering服务端全局过滤不需要filteredRowModel——传给表格的data应当已经是过滤后的结果。但如果你在 features 对象里已经加了filteredRowModel可以用manualFiltering: true让表格跳过它import { useTable, tableFeatures, columnFilteringFeature, globalFilteringFeature, } from tanstack/react-table const features tableFeatures({ columnFilteringFeature, globalFilteringFeature, }) const table useTable({ features, data, columns, manualFiltering: true, })注意使用手动全局过滤时本文后续讨论的许多选项将不再生效。manualFiltering: true意味着表格实例不会对传入的行应用任何全局过滤逻辑而是假定行已经被过滤直接按传入的data原样使用。在模糊搜索示例 main.tsx 中可以看到所有相关选项的注释对照manualFiltering、enableFilters、enableColumnFilters、enableGlobalFilter、filterFromLeafRows、maxLeafRowFilterDepth、getColumnCanGlobalFilter等均以注释形式给出了用途说明。客户端全局过滤特性组合与行模型使用内置客户端全局过滤时只需把globalFilteringFeature连同其前置依赖columnFilteringFeature与filteredRowModel工厂加入 featuresimport { useTable, tableFeatures, columnFilteringFeature, globalFilteringFeature, createFilteredRowModel, filterFn_includesString, } from tanstack/react-table const features tableFeatures({ columnFilteringFeature, globalFilteringFeature, filteredRowModel: createFilteredRowModel(), filterFns: { includesString: filterFn_includesString }, }) const table useTable({ features, // other options... })底层实现createFilteredRowModel.ts揭示了客户端全局过滤的执行顺序读取table.atoms.columnFilters与table.atoms.globalFilter判定是否有全局过滤值globalFilter ! undefined globalFilter ! null globalFilter ! 通过table_getGlobalFilterFn解析全局过滤函数通过column_getCanGlobalFilter筛选出可被全局过滤的列若存在全局过滤值会为每个可过滤列构造一个resolvedGlobalFilter并把__global__加入过滤 id 列表逐行执行任一列过滤失败即整行剔除全局过滤采用任一列命中即保留遇到第一个返回 true 的列就break见 createFilteredRowModel.ts。这个实现揭示了全局过滤的本质语义全局搜索是列之间 OR、行内多过滤器之间是AND。全局过滤函数globalFilterFn12 个内置函数与取值方式globalFilterFn选项决定全局过滤使用的过滤函数其取值有三种方式与 globalFilteringFeature.utils.ts 中的解析逻辑一一对应传入函数本身直接使用传入字符串auto委托给table_getGlobalAutoFilterFn()当前返回filterFn_includesString传入字符串在filterFns注册表中按名查找未注册时开发环境会输出globalFilterFn xxx is not registered警告。const table useTable({ features, data, columns, globalFilterFn: includesString, // built-in filter function })默认情况下有 12 个内置过滤函数可供选择函数名说明includesString大小写不敏感的字符串包含匹配全局过滤默认值includesStringSensitive大小写敏感的字符串包含匹配equalsString大小写不敏感的字符串相等equals严格相等weakEquals弱相等arrIncludes行的数组或字符串值包含至少一个过滤值arrIncludesAll行的数组值包含全部过滤值arrIncludesSome行的数组值包含至少一个过滤值arrHas行的标量值等于至少一个过滤值inNumberRange闭区间[min, max]数字范围端点归一化反向端点自动交换between排他 min/max 区间空白端点视为开区间betweenInclusive包含 min/max 区间空白端点视为开区间补充说明这些函数只是内置注册表的一部分。查看 filterFns.ts 的完整filterFns注册表实际还有startsWith、endsWith、empty、notEmpty、equalsStringSensitive、inDateRange、greaterThan、lessThan、greaterThanOrEqualTo、lessThanOrEqualTo等共 18 个内置函数。注册表导出已被标记为deprecated官方推荐按需导入单个filterFn_*函数以利于 tree-shakingfilterFns.ts。你还可以自定义全局过滤函数并直接传给globalFilterFn详见下文自定义全局过滤函数一节。全局过滤状态三种管理方式globalFilter状态切片保存当前全局过滤值通常是一个搜索字符串切片类型为any以便自定义全局过滤函数接受其他值形态。方式一响应式读取需要触发 UI 重渲染的响应式读取使用table.state.globalFilter在事件处理器里读取当前快照可用table.atoms.globalFilter.get()但该读取不会订阅未来的变更。方式二v9 推荐外部 atom 拥有状态切片在表格外部也需要访问全局过滤状态时例如把过滤值放进服务端过滤的 query key推荐把状态切片交给外部 atom通过atoms表选项传入。atom 保留细粒度订阅过滤值可以在别处使用而不会强制拥有表格的组件重新渲染import { useCreateAtom, useSelector } from tanstack/react-store const globalFilterAtom useCreateAtomstring() // subscribe to the atom wherever you need the value (e.g. for a query key) const globalFilter useSelector(globalFilterAtom) const table useTable({ features, // other options... atoms: { globalFilter: globalFilterAtom, // table.setGlobalFilter now updates globalFilterAtom }, })方式三v8 兼容受控 state onChangev8 风格的state.globalFilter加onGlobalFilterChange模式仍然受支持。它适合简单集成或迁移 v8 代码时使用但粒度不如外部 atom 精细const [globalFilter, setGlobalFilter] useStatestring() const table useTable({ features, // other options... state: { globalFilter, }, onGlobalFilterChange: setGlobalFilter, })两种受控方式的取舍对比详见 Table State Guide。从源码看globalFilteringFeature通过makeStateUpdater(globalFilter, table)生成默认的onGlobalFilterChangeglobalFilteringFeature.tstable.setGlobalFilter实际只是把更新器转发给该回调globalFilteringFeature.utils.ts因此无论是外部 atom、受控 state 还是默认内部状态写入路径都是统一的。在 UI 中添加全局过滤输入框TanStack Table不会为你的表格添加全局过滤输入框需要手动在 UI 中加入。典型做法是在表格上方放置一个输入框响应式读取table.state.globalFilter并用table.setGlobalFilter更新return ( div input value{table.state.globalFilter ?? } onChange{(e) table.setGlobalFilter(String(e.target.value))} placeholderSearch... / /div )生产级实现可以参考模糊搜索示例中的DebouncedInput组件main.tsx它使用tanstack/react-pacer/debouncer的useDebouncedCallback对输入做 500ms 防抖既保证输入手感流畅又避免每次按键都触发全量行模型重算——对大数据集尤其重要。自定义全局过滤函数以模糊搜索为例如果内置函数不满足需求可以自定义过滤函数并传入globalFilterFnconst customFilterFn (row, columnId, filterValue) { return // true if the row should be included in the filtered rows } const table useTable({ features, // other options... globalFilterFn: customFilterFn, })[!NOTE] 一个非常流行的思路是把模糊过滤函数fuzzy filtering用于全局过滤。详见 Fuzzy Filtering Guide。模糊搜索示例 main.tsx 给出了完整的自定义模糊过滤函数实现它基于tanstack/match-sorter-utils的rankItem对单元格值打分通过addMeta把RankingInfo挂到行的columnFiltersMeta上再返回itemRank.passed决定行去留配套的fuzzySort排序函数则按匹配排名排序、排名相同时回退到字母数字排序。注册后通过globalFilterFn: fuzzy启用main.tsx这正是官方文档所说自定义函数注册进filterFns后可按名字引用的实战形态。相关的 match-sorter 工具包源码位于 packages/match-sorter-utils。初始全局过滤状态initialState想在表格初始化时设置全局过滤值可以通过initialState传入如果你自行控制该切片则改为在外部 atom 或 React state 上设置初始值const table useTable({ features, // other options... initialState: { globalFilter: search term, // if not controlling globalFilter state, set initial state here }, })[!NOTE]不要同时使用initialState.globalFilter与受控的globalFilter通过atoms或state受控值会覆盖initialState.globalFilter。这一行为与源码一致globalFilteringFeature的getInitialState返回{ globalFilter: undefined, ...initialState }globalFilteringFeature.ts而table.resetGlobalFilter()无参时克隆initialState.globalFilter、传true时重置为undefinedglobalFilteringFeature.utils.ts。禁用全局过滤默认所有列都参与全局过滤。可以通过列级或表级选项关闭const columns [ { header: () Id, accessorKey: id, enableGlobalFilter: false, // disable global filtering for this column }, //... ] //... const table useTable({ features, // other options... columns, enableGlobalFilter: false, // disable global filtering for all columns })列级enableGlobalFilter: false仅关闭该列的全局过滤表级enableGlobalFilter: false关闭所有列的全局过滤表级enableFilters: false同时关闭列过滤与全局过滤。禁用后该列的column.getCanGlobalFilterAPI 将返回false。从源码看判定逻辑globalFilteringFeature.utils.ts依次检查列级enableGlobalFilter默认 true→ 表级enableGlobalFilter默认 true→ 表级enableFilters默认 true→ 可选的getColumnCanGlobalFilter回调 → 列必须存在 accessor 函数。getColumnCanGlobalFilter的默认实现也值得了解globalFilteringFeature.ts它会在已加载的行中寻找第一个非空值只有当该值类型是string或number时才允许该列参与全局过滤若列数据类型不是 string/number如undefined可自定义getColumnCanGlobalFilter回调覆盖判定。全局过滤 API 速查以下是连接全局过滤 UI 最常用的 APIAPI说明table.setGlobalFilter设置全局过滤值适合接入搜索框的onChange处理器table.resetGlobalFilter将全局过滤值重置为初始状态传table.resetGlobalFilter(true)则清空为undefinedtable.getGlobalFilterFn返回当前全局过滤使用的过滤函数table.getGlobalAutoFilterFn返回默认全局过滤函数当前为includesStringcolumn.getCanGlobalFilter返回该列是否参与全局过滤用于调试哪些列会被搜索这些 API 的类型定义与语义说明可在 globalFilteringFeature.types.ts 中查阅。注意getGlobalAutoFilterFn的注释说明目前它固定返回includesString未来版本可能根据数据形态返回更动态的过滤函数globalFilteringFeature.types.ts。总结全局过滤是 TanStack Table 数据表格体验中最常用也最容易被低估的能力。核心要点回顾特性组合columnFilteringFeature在前、globalFilteringFeature在后客户端过滤还需createFilteredRowModel()两种过滤模型客户端过滤交给行模型自动执行全局过滤跨列 OR、多过滤器 AND服务端过滤用manualFiltering: true跳过行模型让data自带过滤结果并记得在过滤变化处理器中重置服务端分页过滤函数globalFilterFn支持内置字符串名、auto或直接传函数模糊过滤函数是最受欢迎的自定义方向状态管理v9 推荐外部 atom细粒度订阅v8 风格stateonGlobalFilterChange仍受支持initialState.globalFilter仅用于非受控场景性能注意只注册用到的过滤函数以利于 tree-shaking大数据集配合防抖输入框使用。想继续深入可阅读同目录的 Column Filtering Guide、Fuzzy Filtering Guide 以及 Table State Guide并在 examples/react 下运行filters与filters-fuzzy两个示例观察实际效果。【免费下载链接】table Headless UI for building powerful tables datagrids for TS/JS - React-Table, Vue-Table, Solid-Table, Svelte-Table项目地址: https://gitcode.com/gh_mirrors/ta/table创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考