如何在Tanstack React-Table全局过滤器中实现精确匹配?
在TanStack React Table中实现带精确匹配的全局过滤器
需求描述
我想在TanStack React Table的全局过滤器里实现类似谷歌搜索的逻辑——用双引号包裹关键词时触发精确匹配,比如搜索"male"时,不会返回包含female的行。我写了初步的匹配逻辑,但不知道怎么覆盖默认的全局过滤器函数,附上了可运行的全局搜索示例代码,求具体实现方法。
我的初步匹配逻辑(未测试):
function getRandomBoolean = (filter, row) => { const searchTerm = filter.value.trim(); if (searchTerm.startsWith('"') && searchTerm.endsWith('"')) { // Perform an exact match search if the search term is enclosed in quotes const exactSearchTerm = searchTerm.slice(1, -1); return row === exactSearchTerm; } else { // Perform a regular search if no quotes are used return row.toLowerCase().includes(searchTerm.toLowerCase()); } }
实现步骤
1. 修正并完善自定义全局过滤函数
原函数存在语法错误、参数不匹配React Table规范、引号判断逻辑错误等问题,修正后的函数如下:
const customGlobalFilter = (rows, id, filterValue) => { const searchTerm = filterValue.trim(); if (!searchTerm) return rows; // 精确匹配:处理双引号包裹的关键词 if (searchTerm.startsWith('"') && searchTerm.endsWith('"')) { const exactTerm = searchTerm.slice(1, -1).toLowerCase(); return rows.filter(row => { // 遍历所有单元格,存在一个精确匹配则保留该行 return Object.values(row.values).some(cellValue => { // 统一转字符串处理,兼容数值类型 return String(cellValue).toLowerCase() === exactTerm; }); }); } // 普通模糊匹配:大小写不敏感 const lowerTerm = searchTerm.toLowerCase(); return rows.filter(row => { return Object.values(row.values).some(cellValue => { return String(cellValue).toLowerCase().includes(lowerTerm); }); }); };
2. 在useTable中配置自定义过滤函数
在useTable的配置对象中添加globalFilterFn属性,传入自定义函数即可覆盖默认逻辑:
const tableInstance = useTable({ columns: columns, data: data, globalFilterFn: customGlobalFilter // 绑定自定义全局过滤函数 }, useGlobalFilter);
完整修改后的代码
import React, { useMemo } from 'react' import { useTable, useGlobalFilter } from 'react-table' const COLUMNS = [ { Header: 'id', accessor: 'id' }, { Header: 'First name', accessor: 'first_name' }, { Header: 'Last name', accessor: 'last_name' }, { Header: 'Mail', accessor: 'email' }, { Header: 'gender', accessor: 'gender' }, { Header: 'age', accessor: 'age' }, { Header: 'country', accessor: 'country' }, { Header: 'Phone', accessor: 'phone' } ]; const MOCK_DATA = [ {"id":1,"first_name":"Abey","last_name":"Shattock","email":"ashattock0@who.int","gender":"male","age":60,"country":"Sweden","phone":"3235563967"}, {"id":2,"first_name":"Gert","last_name":"Verey","email":"gverey1@miitbeian.gov.cn","gender":"male","age":39,"country":"Argentina","phone":"6617228260"}, {"id":3,"first_name":"Elsa","last_name":"McDermott-Row","email":"gmcdermottrow2@fc2.com","gender":"female","age":73,"country":"China","phone":"5049019528"}, {"id":4,"first_name":"Ade","last_name":"Southwick","email":"asouthwick3@gmpg.org","gender":"male","age":58,"country":"France","phone":"2562514369"}, {"id":5,"first_name":"Angelina","last_name":"Almond","email":"aalmond4@ezinearticles.com","gender":"Female","age":30,"country":"Paraguay","phone":"9509201868"}, ]; export const GlobalFilter = ({filter, setFilter}) => { return ( <span> Search: {' '} <input value={filter || ''} onChange={(e) => setFilter(e.target.value)} /> </span> ) } export const BasicTable = () => { const columns = useMemo(() => COLUMNS, []); const data = useMemo(() => MOCK_DATA, []); // 自定义全局过滤函数 const customGlobalFilter = (rows, id, filterValue) => { const searchTerm = filterValue.trim(); if (!searchTerm) return rows; // 精确匹配:双引号包裹关键词 if (searchTerm.startsWith('"') && searchTerm.endsWith('"')) { const exactTerm = searchTerm.slice(1, -1).toLowerCase(); return rows.filter(row => { return Object.values(row.values).some(cellValue => { return String(cellValue).toLowerCase() === exactTerm; }); }); } // 普通模糊匹配 const lowerTerm = searchTerm.toLowerCase(); return rows.filter(row => { return Object.values(row.values).some(cellValue => { return String(cellValue).toLowerCase().includes(lowerTerm); }); }); }; const tableInstance = useTable({ columns: columns, data: data, globalFilterFn: customGlobalFilter // 覆盖默认全局过滤函数 }, useGlobalFilter); const {getTableProps, getTableBodyProps, prepareRow, state, setGlobalFilter, headerGroups, rows } = tableInstance; const { globalFilter } = state; return ( <div> <GlobalFilter filter={globalFilter} setFilter={setGlobalFilter}/> <table { ...getTableProps() }> <thead> {headerGroups.map(headerGroup => ( <tr {...headerGroup.getHeaderGroupProps()}> {headerGroup.headers.map(column => ( <th {...column.getHeaderProps()}>{column.render('Header')}</th> ))} </tr> ))} </thead> <tbody { ...getTableBodyProps() }> {rows.map(row => { prepareRow(row); return ( <tr {...row.getRowProps()}> {row.cells.map(cell => ( <td {...cell.getCellProps()}> {cell.render('Cell')}</td> ))} </tr> ); })} </tbody> </table> </div> ) }
效果说明
- 输入
male:模糊匹配所有包含male/Female的行(大小写不敏感) - 输入
"male":仅返回gender字段精确等于male的行(不会匹配female) - 输入
"Female":仅返回gender字段为Female的行
内容的提问来源于stack exchange,提问作者starking
相关产品推荐
相关产品推荐

