如何在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
相关产品推荐
相关产品推荐

