You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TanStack Table(React-Table):如何将列筛选状态转为后端预期格式?

解决React表格筛选状态转nestjs-paginate格式的问题

这两个方案其实各有适用场景,我帮你拆解下优劣,再给你具体的代码示例:

方案1:列定义中直接绑定filterFn(适合小型项目/列少的场景)

这个方案的核心是把每列对应的后端筛选操作符直接写在列定义的filterFn属性里,前端筛选时直接调用这个函数生成后端需要的格式。优点是直观,每列的筛选逻辑和列定义绑定在一起,不用额外维护映射关系;缺点是列多的时候会有重复代码。

示例代码:

首先定义带filterFn的列:

import { ColumnDef } from '@tanstack/react-table';

// 假设你的表格数据类型是User
type User = {
  id: number;
  name: string;
  age: number;
  email: string;
};

const columnDefs: ColumnDef<User>[] = [
  {
    id: 'name',
    header: '姓名',
    accessorKey: 'name',
    // 姓名用精确匹配$eq
    filterFn: (value: unknown) => ({ $eq: value }),
  },
  {
    id: 'age',
    header: '年龄',
    accessorKey: 'age',
    // 年龄用大于$gt,同时把unknown的value转成数字
    filterFn: (value: unknown) => ({ $gt: Number(value) }),
  },
  {
    id: 'email',
    header: '邮箱',
    accessorKey: 'email',
    // 邮箱用模糊匹配$like,自动加通配符
    filterFn: (value: unknown) => ({ $like: `%${value}%` }),
  },
];

然后写转换函数:

import { ColumnFiltersState } from '@tanstack/react-table';

const convertToNestJsFilters = (filters: ColumnFiltersState, columns: ColumnDef<User>[]) => {
  const nestJsFilters: Record<string, any> = {};
  
  filters.forEach(filter => {
    const column = columns.find(col => col.id === filter.id);
    if (column?.filterFn) {
      // 调用列定义里的filterFn生成对应格式
      nestJsFilters[column.accessorKey || column.id] = column.filterFn(filter.value);
    }
  });
  
  return nestJsFilters;
};

使用的时候,拿到表格的columnFilters状态,调用这个函数就能得到后端需要的格式,比如:

// 假设表格的筛选状态是:[{ id: 'age', value: '20' }, { id: 'name', value: '张三' }]
const converted = convertToNestJsFilters(columnFilters, columnDefs);
// 转换结果:{ age: { $gt: 20 }, name: { $eq: '张三' } }

方案2:自定义列Meta+通用映射函数(适合中大型项目/列多的场景)

这个方案更具扩展性,我们给列定义加一个自定义的meta属性来指定筛选操作符,然后写一个通用的映射函数来统一转换。优点是逻辑集中,新增列只需要配置meta,不用修改转换函数;缺点是需要额外定义类型,初期要多写一点代码。

示例代码:

首先定义带Meta的列类型:

import { ColumnDef } from '@tanstack/react-table';

// 自定义Meta类型,支持nestjs-paginate的所有筛选操作符
type FilterMeta = {
  filterOperator: '$eq' | '$gt' | '$lt' | '$like' | '$in' | string;
  // 可选:如果需要特殊处理值,可以加个transform函数
  valueTransform?: (value: unknown) => unknown;
};

// 扩展ColumnDef,加入自定义Meta
type CustomColumnDef<T> = ColumnDef<T> & {
  meta?: FilterMeta;
};

// 表格数据类型
type User = {
  id: number;
  name: string;
  age: number;
  email: string;
};

然后定义列:

const columnDefs: CustomColumnDef<User>[] = [
  {
    id: 'name',
    header: '姓名',
    accessorKey: 'name',
    meta: { filterOperator: '$eq' },
  },
  {
    id: 'age',
    header: '年龄',
    accessorKey: 'age',
    meta: { 
      filterOperator: '$gt',
      valueTransform: (val) => Number(val) // 把字符串转成数字
    },
  },
  {
    id: 'email',
    header: '邮箱',
    accessorKey: 'email',
    meta: { 
      filterOperator: '$like',
      valueTransform: (val) => `%${val}%` // 自动加模糊匹配通配符
    },
  },
];

然后写通用转换函数:

import { ColumnFiltersState } from '@tanstack/react-table';

const convertToNestJsFilters = (filters: ColumnFiltersState, columns: CustomColumnDef<User>[]) => {
  const nestJsFilters: Record<string, Record<string, unknown>> = {};
  
  filters.forEach(filter => {
    const column = columns.find(col => col.id === filter.id);
    const meta = column?.meta;
    
    if (!meta?.filterOperator) return;
    
    // 处理值转换,没有transform就用原始值
    let filterValue = meta.valueTransform ? meta.valueTransform(filter.value) : filter.value;
    
    // 生成nestjs-paginate需要的格式
    nestJsFilters[column.accessorKey || column.id] = {
      [meta.filterOperator]: filterValue,
    };
  });
  
  return nestJsFilters;
};

方案选择建议

  • 如果你的表格只有几列,后续不会频繁新增,方案1足够简单直接,不用额外维护类型和映射逻辑;
  • 如果你的表格列很多,或者后续会不断新增列,方案2更优,因为它把筛选逻辑集中管理,新增列只需要配置meta,不用修改转换函数,扩展性更强。

最后,转换后的格式可以用qs库序列化成URL查询参数(nestjs-paginate默认从query里取filter参数):

import qs from 'qs';

const filterQuery = qs.stringify({ filter: convertedFilters }, { encodeValuesOnly: true });
// 比如得到:filter[age][$gt]=20&filter[name][$eq]=张三
// 然后拼到请求URL里即可

内容的提问来源于stack exchange,提问作者monotype

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 18:20:59