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

如何在ReactJS中使用TanStack Table实现多输入框全局筛选?

解决TanStack Table多条件全局筛选(搜索/分类/价格范围)问题

核心思路

TanStack Table默认的globalFilter仅支持字符串类型,要实现多维度筛选,需要:

  • 定义复合筛选状态,包含搜索关键词、分类、价格范围三个维度
  • 替换默认的globalFilterFn,实现基于复合状态的自定义过滤逻辑
  • 让表格监听自定义筛选状态的变化,自动触发数据重筛

具体实现步骤

1. 定义筛选状态类型(TypeScript)

先给筛选状态声明类型,保证类型安全:

// 假设你的API返回商品数据类型为Product
type Product = {
  id: string;
  name: string;
  category: string;
  price: number;
  // 其他字段...
};

// 自定义筛选条件类型
type TableFilters = {
  search: string;
  category: string;
  priceRange: { min: number; max: number };
};

// 初始筛选状态
const initialFilters: TableFilters = {
  search: '',
  category: '',
  priceRange: { min: 0, max: Infinity },
};

2. 管理筛选状态

用React的useState管理自定义筛选状态:

const [filters, setFilters] = useState<TableFilters>(initialFilters);

3. 编写自定义全局筛选函数

实现globalFilterFn,对每一行数据进行多条件校验:

const globalFilterFn: GlobalFilterFn<Product> = (row, filter) => {
  const { search, category, priceRange } = filter as TableFilters;
  const product = row.original;

  // 搜索关键词模糊匹配(商品名称)
  const matchesSearch = product.name.toLowerCase().includes(search.toLowerCase());

  // 分类匹配(空值则跳过该维度筛选)
  const matchesCategory = !category || product.category === category;

  // 价格范围匹配
  const matchesPrice = product.price >= priceRange.min && product.price <= priceRange.max;

  // 所有条件满足才保留该行
  return matchesSearch && matchesCategory && matchesPrice;
};

4. 配置useReactTable

在表格配置中替换默认的全局筛选参数,绑定自定义状态与筛选函数:

const table = useReactTable({
  data: products, // TanStack Query获取到的商品数据
  columns, // 你的表格列配置
  globalFilter: filters, // 使用自定义复合筛选状态
  globalFilterFn, // 使用自定义筛选逻辑
  state: {
    globalFilter: filters,
  },
  onGlobalFilterChange: (newFilter) => {
    // 更新自定义筛选状态
    setFilters(newFilter as TableFilters);
  },
});

5. 渲染Shadcn UI筛选控件

将搜索框、分类选择器、价格范围输入框与筛选状态绑定:

// 搜索输入框
<Input
  placeholder="搜索商品名称"
  value={filters.search}
  onChange={(e) => setFilters(prev => ({ ...prev, search: e.target.value }))}
  className="mb-4 w-full max-w-md"
/>

// 分类选择器
<Select value={filters.category} onValueChange={(value) => setFilters(prev => ({ ...prev, category: value }))}>
  <SelectTrigger className="w-full max-w-md mb-4">
    <SelectValue placeholder="选择分类" />
  </SelectTrigger>
  <SelectContent>
    <SelectItem value="">全部分类</SelectItem>
    <SelectItem value="electronics">电子产品</SelectItem>
    <SelectItem value="clothing">服装</SelectItem>
    {/* 其他分类选项 */}
  </SelectContent>
</Select>

// 价格范围输入组
<div className="flex gap-2 mb-4 max-w-md">
  <Input
    type="number"
    placeholder="最低价格"
    value={filters.priceRange.min || ''}
    onChange={(e) => setFilters(prev => ({
      ...prev,
      priceRange: { ...prev.priceRange, min: Number(e.target.value) || 0 }
    }))}
  />
  <span className="self-center">-</span>
  <Input
    type="number"
    placeholder="最高价格"
    value={filters.priceRange.max === Infinity ? '' : filters.priceRange.max}
    onChange={(e) => setFilters(prev => ({
      ...prev,
      priceRange: { ...prev.priceRange, max: e.target.value ? Number(e.target.value) : Infinity }
    }))}
  />
</div>

性能优化(可选)

用useMemo缓存筛选状态与筛选函数,避免不必要的重渲染:

const memoizedFilters = useMemo(() => filters, [filters]);
const memoizedGlobalFilterFn = useMemo(() => globalFilterFn, []);

// 在useReactTable中使用缓存后的值
const table = useReactTable({
  // ...其他配置
  globalFilter: memoizedFilters,
  globalFilterFn: memoizedGlobalFilterFn,
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 23:32:19