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

如何为Material React Table的State列实现文本搜索+多选过滤?

如何在Material React Table的State列同时实现文本搜索与多选过滤?

Material React Table的filterVariant属性仅支持单一过滤类型(如"multi-select"或"text"),无法通过传入数组形式同时启用两种过滤方式。以下是两种可行的解决方案:


方案一:自定义组合过滤组件(客户端过滤)

通过自定义Filter组件,将文本输入框与多选下拉框组合,再配合自定义过滤函数实现复合过滤逻辑。

代码修改步骤:

  1. 导入Material UI的Select和MenuItem组件(如果未导入)
  2. 编写自定义过滤组件
  3. 实现复合过滤函数
  4. 更新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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 22:48:10