Material UI Table行筛选异常问题排查求助
搜索功能问题排查:控制台输出匹配行但表格无变化,赋值结果后TextField只读
问题描述
在TextField中执行搜索时,匹配的行能在控制台正确输出,但表格完全没有变化。尝试将搜索结果赋值给新数组后,TextField变为只读状态,恳请协助排查该问题。
现有代码
状态设置与数据获取函数
const [rows, setRows]: any = useState([]); const [checked, setChecked]: any = useState(false); const [selected, setSelected] = React.useState<readonly string[]>([]); useEffect(() => { if (!checked) { setChecked(true); fetchData(); } }, [checked]); const fetchData: any = async () => { const response: any = await axios.get(`/api/layer_data`); setChecked(true); let dataRows: any[] = response.data; dataRows.map((dataRow: any) => (dataRow.isSelected = false)); console.log('response: ', response.data); setRows(dataRows); };
数据筛选handleSearch函数
const handleSearch = (e: any) => { const inputSearch = e.target.value; rows.filter((row: any) => { if (inputSearch == '') { return rows; } else if (row.product_id == inputSearch) { console.log(row); return row; } else if (row.sku_id == inputSearch) { console.log(row); return row; } else if (row.description == inputSearch) { console.log(row); return row; } else if (row.units_per_layer == inputSearch) { console.log(row); return row; } else if (row.in_stock == inputSearch) { console.log(row); return row; } else if (row.bin == inputSearch) { console.log(row); return row; } }); };
TextField定义
<TextField onChange={(e) => handleSearch(e)} label="Search..." fullWidth variant="outlined" className={style.padding_right} />
表格渲染映射函数
{rows.sort(getComparator(order, orderBy)).map((row: any, index: any) => { const isItemSelected = isSelected(row.product_id); const labelId = `enhanced-table-checkbox-${index}`; return ( <StyledTableRow hover onClick={(event) => handleClick(event, row.product_id)} role="checkbox" aria-checked={isItemSelected} tabIndex={-1} key={row.product_id} selected={isItemSelected} > <StyledTableCell padding="checkbox"> <Checkbox color="primary" checked={row.isSelected} inputProps={{ 'aria-labelledby': labelId }} onChange={handleCheckbox} value={index} /> </StyledTableCell> <StyledTableCell align="right"> <input type="number" min="0" required defaultValue="0" onChange={(e) => handleInput(e, index)} /> </StyledTableCell> <StyledTableCell align="right">{row.sku_id}</StyledTableCell> <StyledTableCell component="th" id={labelId} scope="row" padding="none" align="right"> {row.product_id} </StyledTableCell> <StyledTableCell align="right">{row.in_stock}</StyledTableCell> <StyledTableCell align="right">{row.bin}</StyledTableCell> <StyledTableCell align="right">{row.units_per_layer}</StyledTableCell> <StyledTableCell align="right">{row.description}</StyledTableCell> </StyledTableRow> ); })}
问题排查与修复
核心问题分析
- 表格无变化:
handleSearch中仅执行了filter操作,但未将过滤结果通过setRows更新状态,React无法感知数据变化,因此表格不会重新渲染。同时filter回调返回值逻辑错误(应返回布尔值而非数组/对象)。 - TextField变只读:若直接用过滤结果覆盖
rows状态,会丢失原始数据。当输入清空时,无法恢复完整数据集,导致后续搜索无数据可过滤,表现为TextField"只读"。
修复步骤
1. 新增状态存储原始数据
添加originalRows状态保存接口返回的完整数据,确保过滤始终基于原始数据集操作:
const [rows, setRows]: any = useState([]); const [originalRows, setOriginalRows]: any = useState([]); // 新增状态 const [checked, setChecked]: any = useState(false); const [selected, setSelected] = React.useState<readonly string[]>([]); const fetchData: any = async () => { const response: any = await axios.get(`/api/layer_data`); setChecked(true); let dataRows: any[] = response.data; dataRows.map((dataRow: any) => (dataRow.isSelected = false)); console.log('response: ', response.data); setRows(dataRows); setOriginalRows(dataRows); // 保存原始数据 };
2. 重写handleSearch函数
修正过滤逻辑,更新状态并支持清空输入恢复原始数据:
const handleSearch = (e: any) => { const inputSearch = e.target.value.trim(); // 清空输入时恢复原始数据 if (!inputSearch) { setRows(originalRows); return; } // 基于原始数据过滤,返回布尔值判断匹配 const filteredRows = originalRows.filter((row: any) => { return row.product_id === inputSearch || row.sku_id === inputSearch || row.description === inputSearch || row.units_per_layer === inputSearch || row.in_stock === inputSearch || row.bin === inputSearch; }); console.log(filteredRows); setRows(filteredRows); // 更新状态触发表格渲染 };
3. 优化表格排序逻辑
rows.sort()会直接修改原数组(违反React状态不可变原则),需先复制数组再排序:
{[...rows].sort(getComparator(order, orderBy)).map((row: any, index: any) => { // 原渲染逻辑保持不变 })}
额外建议
- 避免使用
any类型,给状态和函数定义明确的TypeScript类型,减少潜在错误。 - 若需要模糊搜索,可将匹配逻辑改为
row.product_id.includes(inputSearch),并统一转小写避免大小写敏感问题。 - 数据量较大时,用
useMemo缓存过滤结果,减少不必要的重渲染。
内容的提问来源于stack exchange,提问作者Blake Lucey
相关产品推荐
相关产品推荐

