ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

深入解析 TanStack Table 的 createFacetedUniqueValues:构建分面过滤(Faceted Filter)唯一值统计的核心工厂

深入解析 TanStack Table 的 createFacetedUniqueValues:构建分面过滤(Faceted Filter)唯一值统计的核心工厂 深入解析 TanStack Table 的 createFacetedUniqueValues构建分面过滤Faceted Filter唯一值统计的核心工厂【免费下载链接】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本仓库 table-core 包中createFacetedUniqueValues工厂函数展开讲解它如何为分面过滤Faceted Filtering生成该列当前可选值及其出现次数的 Memoized 统计 Map并揭示其与分面行模型Faceted Row Model、全局过滤上下文的协作原理。读完本文你将掌握该函数的完整签名、内部去重计数逻辑、__global__特殊上下文的行为以及如何在 React 等示例中用它驱动过滤下拉框的候选列表与占位文案。函数概览分面过滤 UI 的数据基石在分面过滤场景中UI 需要为每一列展示当前数据里到底有哪些可选值、每个值出现了多少次从而让用户在下拉框中快速筛选。createFacetedUniqueValues正是为此设计的工厂函数——它接受表格配置返回一个按列生成统计 Map的函数该函数再基于表格的行模型Row Model与相关过滤状态推导分面数据。它定义于 createFacetedUniqueValues.ts并被导出为columnFacetingFeature列分面特性的一部分见 columnFacetingFeature.ts。完整类型签名与类型参数官方 API 文档createFacetedUniqueValues.md给出的签名为function createFacetedUniqueValuesTFeatures, TData(): (table, columnId) () Mapany, number;具体展开如下类型参数TFeatures必须继承TableFeatures即当前表格启用的特性集合类型类型参数TData必须继承RowData默认值为any表示表格行数据类型返回值一个柯里化函数先接收table类型为TableTFeatures,TData与columnIdstring再次调用后返回Mapany, number—— 键是列中出现的唯一值值是它在当前分面行模型中的出现次数。从源码看该工厂的完整实现结构如下createFacetedUniqueValues.tsexport function createFacetedUniqueValues TFeatures extends TableFeatures, TData extends RowData any, (): ( table: TableTFeatures, TData, columnId: string, ) () Mapany, number { return (_table, columnId) { const table _table as unknown as Table_InternalTFeatures, TData return tableMemo({ feature: columnFacetingFeature, table, fnName: table.getFacetedUniqueValues, memoDeps: () { if (columnId __global__) { return [ callMemoOrStaticFn( table, getGlobalFacetedRowModel, table_getGlobalFacetedRowModel, ).flatRows, ] } const column table.getColumn(columnId) if (!column) return [table.getPreFilteredRowModel().flatRows] return [ callMemoOrStaticFn( column, getFacetedRowModel, column_getFacetedRowModel, table, ).flatRows, ] }, fn: (flatRows) _createFacetedUniqueValues(table, columnId, flatRows), }) } }记忆化机制tableMemo 与依赖收集该工厂的核心是tableMemo包装。tableMemo是 table-core 提供的表格感知的记忆化函数在memo基础上叠加了调试选项与特性元数据使行模型和派生 API 共享一致的诊断信息见 utils.ts。memoDeps决定了结果何时失效当columnId __global__全局过滤上下文时依赖为table.getGlobalFacetedRowModel().flatRows——即全局分面行模型的扁平行数组当传入的是某个具体列且该列存在时依赖为该列的getFacetedRowModel().flatRows当传入的列不存在时回退到table.getPreFilteredRowModel().flatRows预过滤行模型。这意味着只要底层的分面行模型不变例如其他列的过滤条件没有变化重复调用会直接命中缓存返回同一份Map实例保证引用稳定性——这正是分面 UI 中依赖引用比较如 React 的useMemo/useEffect依赖数组所需要的。分面行模型从哪来与 createFacetedRowModel 的协作统计唯一值之前必须先确定在哪些行上统计。这是由分面行模型Faceted Row Model决定的其工厂为 createFacetedRowModel.ts。分面行模型的关键语义是排除本列自身的过滤器统计某列的可选值时该列当前已选的过滤条件不应影响候选项否则选了一个值后其他值会消失。源码中通过if (id ! columnId) filterableIds.push(id)剔除本列保留其他列的过滤器其他列的过滤仍然生效因此统计结果会随其他列的筛选实时收窄全局上下文__global__排除全局过滤器自身if (hasGlobalFilter columnId ! __global__) filterableIds.push(__global__)与列自身排除过滤器的逻辑对称无过滤时直接返回预过滤行模型当既没有列过滤器也没有全局过滤器时_createFacetedRowModel直接返回preRowModel避免多余计算。测试用例columnFacetingFeature.test.ts验证了这些语义当只有status列被过滤时status列的分面行模型等于预过滤行模型而firstName列的分面行模型仍会应用status列的过滤。唯一值统计的核心实现_createFacetedUniqueValues真正的计数逻辑在内部函数_createFacetedUniqueValues中createFacetedUniqueValues.tsfunction _createFacetedUniqueValues TFeatures extends TableFeatures, TData extends RowData any, ( table: Table_InternalTFeatures, TData, columnId: string, flatRows: ArrayRowTFeatures, TData, ): Mapany, number { const columnIds columnId __global__ ? table .getAllLeafColumns() .filter((column) column_getCanGlobalFilter(column)) .map((column) column.id) : [columnId] const facetedUniqueValues new Mapany, number() for (let i 0; i flatRows.length; i) { for (let c 0; c columnIds.length; c) { const values flatRows[i]!.getUniqueValues(columnIds[c]!) as Arrayunknown | undefined if (!values) continue for (let j 0; j values.length; j) { const value values[j] const previousValue facetedUniqueValues.get(value) facetedUniqueValues.set( value, previousValue undefined ? 1 : previousValue 1, ) } } } return facetedUniqueValues }几个值得注意的实现细节__global__聚合多列全局上下文会把所有参与全局过滤的叶子列通过column_getCanGlobalFilter判断的取值合并统计到一个 Map 中从而反映全局搜索框可匹配到的所有值多值列支持每一行通过getUniqueValues(columnId)取得该列的取值数组因此一个单元格含有多个值如标签数组时每个值都会参与计数undefined 值不丢弃对没有访问器accessor的列getUniqueValues可能返回undefined此时直接continue跳过但列本身取值为undefined的行会被正常计入 Map键为undefined。测试 columnFacetingFeature.test.ts 断言对status列统计时active出现 2 次、undefined出现 1 次二者都在结果 Map 中计数方式遍历所有扁平行与目标列用Map.get/set完成累加最终返回Mapany, number。缓存与静态函数columnFacetingFeature 的配套设施createFacetedUniqueValues生成的结果并非直接暴露给用户而是通过columnFacetingFeature特性挂载到列原型与表格实例上列 APIcolumn.getFacetedUniqueValues()另有getFacetedRowModel()、getFacetedMinMaxValues()表格 APItable.getGlobalFacetedUniqueValues()另有getGlobalFacetedRowModel()、getGlobalFacetedMinMaxValues()缓存位置table._rowModels.facetedUniqueValues与table._rowModels.globalFacetedUniqueValues按列 id 惰性初始化并缓存工厂函数见 columnFacetingFeature.utils.ts。columnFacetingFeature特意不在特性层重复记忆化官方注释明确说明内置的createFaceted*工厂内部已自行 memoize若外层再加一层缓存会冻结那些数据变化独立于分面行模型的自定义工厂自定义工厂应自行负责记忆化见 columnFacetingFeature.ts。对应的类型声明在 columnFacetingFeature.types.tsColumn_ColumnFaceting.getFacetedUniqueValues: () Mapany, number以及Table_ColumnFaceting.getGlobalFacetedUniqueValues。缓存行为的正确性由测试覆盖columnFacetingFeature.test.ts对同一列的column_getFacetedRowModel、column_getFacetedMinMaxValues、column_getFacetedUniqueValues与对应全局函数各调用两次底层工厂函数只被调用一次列上下文一次、__global__上下文一次验证了按列 全局上下文两级缓存只做惰性初始化。在 React 示例中的真实用法在仓库的 React 分面过滤示例filters-faceted/src/main.tsx中过滤组件这样消费唯一值统计const sortedUniqueValues React.useMemo( () filterVariant range ? [] : Array.from(column.getFacetedUniqueValues().keys()) .sort() .slice(0, 5000), [column.getFacetedUniqueValues(), filterVariant], )通过Array.from(column.getFacetedUniqueValues().keys())取出所有唯一值作为下拉选项候选.slice(0, 5000)限制候选数量避免超大列拖垮渲染useMemo的依赖直接使用column.getFacetedUniqueValues()的返回结果——这正是前面提到的Map 引用稳定性发挥作用的地方只有行模型真正变化时才会重新计算从而避免不必要的重渲染同文件中还用column.getFacetedUniqueValues().size生成下拉框占位文案Search... (N)直观展示当前可选值数量。其它框架Vue、Svelte、Solid、Angular、Lit 等的filters-faceted示例采用了相同的 API 模式只是换成了对应框架的响应式写法。使用前提与注意事项需要启用特性与工厂getFacetedUniqueValues依赖columnFacetingFeature特性以及facetedUniqueValues行模型工厂。典型装配方式与测试一致const features testFeatures({ columnFacetingFeature, columnFilteringFeature, facetedMinMaxValues: createFacetedMinMaxValues(), facetedRowModel: createFacetedRowModel(), facetedUniqueValues: createFacetedUniqueValues(), filteredRowModel: createFilteredRowModel(), filterFns, })未注册工厂时的回退若未配置facetedUniqueValues工厂column_getFacetedUniqueValues会返回一个稳定共享的空 MapcreateStableEmptyMapFn保证每次读取同一实例见 columnFacetingFeature.utils.tsUI 不应假设结果非空自定义工厂的自主记忆化替换默认工厂时需要自行保证返回结果的引用稳定否则下游 UI 的依赖比较会失效统计口径结果是当前分面行模型下的统计会随其他列过滤条件变化而动态收窄这是分面过滤的预期行为若需展示全量候选应结合自定义行模型工厂实现。小结createFacetedUniqueValues是 TanStack Table 分面过滤体系的统计引擎它用tableMemo保证记忆化与引用稳定依赖分面行模型确定统计范围用Mapany, number输出唯一值及出现次数并通过__global__特殊列 id 支持全局过滤的跨列聚合。理解它的签名、依赖收集与缓存语义是正确构建高性能分面过滤下拉框、数值范围筛选与可选项随其他筛选实时收窄等交互的前提。【免费下载链接】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),仅供参考
返回列表