如何为Material React Table的State列实现文本搜索+多选过滤?
如何在Material React Table的State列同时实现文本搜索与多选过滤?
Material React Table的filterVariant属性仅支持单一过滤类型(如"multi-select"或"text"),无法通过传入数组形式同时启用两种过滤方式。以下是两种可行的解决方案:
方案一:自定义组合过滤组件(客户端过滤)
通过自定义Filter组件,将文本输入框与多选下拉框组合,再配合自定义过滤函数实现复合过滤逻辑。
代码修改步骤:
- 导入Material UI的
Select和MenuItem组件(如果未导入) - 编写自定义过滤组件
- 实现复合过滤函数
- 更新State列的配置
完整代码示例:
import React, { useMemo, useState, useEffect } from 'react'; import { MaterialReactTable } from 'material-react-table'; import { Select, MenuItem } from '@mui/material'; //新增导入 import { citiesList, data, usStateList } from './makeData'; // 自定义State列过滤组件 const StateFilter = ({ column, filter, onChange }) => { const [textFilter, setTextFilter] = useState(''); const [multiSelectFilter, setMultiSelectFilter] = useState([]); // 同步外部过滤状态 useEffect(() => { if (filter) { setTextFilter(filter.text || ''); setMultiSelectFilter(filter.multiSelect || []); } }, [filter]); // 合并过滤条件并触发回调 const handleFilterChange = () => { onChange({ text: textFilter, multiSelect: multiSelectFilter, }); }; return ( <div style={{ display: 'flex', flexDirection: 'column', gap: '8px', padding: '4px' }}> <input type="text" placeholder="搜索州名" value={textFilter} onChange={(e) => { setTextFilter(e.target.value); handleFilterChange(); }} style={{ padding: '6px', borderRadius: '4px', border: '1px solid #e0e0e0' }} /> <Select multiple value={multiSelectFilter} onChange={(e) => { setMultiSelectFilter(e.target.value); handleFilterChange(); }} renderValue={(selected) => selected.join(', ')} size="small" style={{ minWidth: 200 }} > {usStateList.map((state) => ( <MenuItem key={state} value={state}> {state} </MenuItem> ))} </Select> </div> ); }; // 自定义复合过滤函数 const stateFilterFn = (row, columnId, filterValue) => { const stateValue = row.getValue(columnId); // 文本过滤:空输入则匹配所有,否则模糊匹配(不区分大小写) const textMatch = !filterValue.text || stateValue.toLowerCase().includes(filterValue.text.toLowerCase()); // 多选过滤:无选中项则匹配所有,否则必须在选中列表中 const multiSelectMatch = filterValue.multiSelect.length === 0 || filterValue.multiSelect.includes(stateValue); // 两个条件都满足才保留该行 return textMatch && multiSelectMatch; }; const Example = () => { const columns = useMemo( () => [ // 其他列配置保持不变 { header: 'Status', accessorFn: (originalRow) => (originalRow.isActive ? 'true' : 'false'), id: 'isActive', filterVariant: 'checkbox', Cell: ({ cell }) => cell.getValue() === 'true' ? 'Active' : 'Inactive', size: 170, }, { accessorKey: 'name', header: 'Name', filterVariant: 'text', size: 100, }, { accessorKey: 'age', header: 'Age', filterVariant: 'range', filterFn: 'between', size: 80, }, { accessorKey: 'salary', header: 'Salary', Cell: ({ cell }) => cell.getValue().toLocaleString('en-US', { style: 'currency', currency: 'USD', }), filterVariant: 'range-slider', filterFn: 'betweenInclusive', muiTableHeadCellFilterSliderProps: { marks: true, max: 200_000, min: 30_000, step: 10_000, valueLabelFormat: (value) => value.toLocaleString('en-US', { style: 'currency', currency: 'USD', }), }, }, { accessorKey: 'city', header: 'City', filterVariant: 'select', filterSelectOptions: citiesList, }, // 修改后的State列配置 { accessorKey: 'state', header: 'State', Filter: StateFilter, //使用自定义过滤组件 filterFn: stateFilterFn, //使用自定义过滤函数 filterSelectOptions: usStateList, }, ], [], ); return ( <MaterialReactTable columns={columns} data={data} initialState={{ showColumnFilters: true }} /> ); }; export default Example;
方案二:服务端复合过滤
如果你的表格数据是通过服务端接口获取的,可以开启filterMode: 'server',将文本和多选的过滤条件传递给后端,由后端处理复合过滤逻辑。
核心代码修改:
// 在表格组件中添加服务端过滤配置 <MaterialReactTable columns={columns} data={data} initialState={{ showColumnFilters: true }} filterMode="server" //开启服务端过滤 onColumnFiltersChange={async (filters) => { // 提取State列的过滤条件 const stateFilter = filters.find(f => f.id === 'state'); const stateText = stateFilter?.value?.text || ''; const stateMultiSelect = stateFilter?.value?.multiSelect?.join(',') || ''; // 发送请求到后端,携带过滤参数 const response = await fetch(`/your-api-endpoint?stateText=${encodeURIComponent(stateText)}&stateMultiSelect=${encodeURIComponent(stateMultiSelect)}`); const newData = await response.json(); // 更新表格数据(需要提前用useState声明data状态) setData(newData); }} />
此时State列的配置仍需使用自定义Filter组件来收集两种过滤条件,与方案一的自定义组件部分一致。
内容的提问来源于stack exchange,提问作者Deepak
相关产品推荐
相关产品推荐

