material-table中onRowAdd/onRowUpdate后筛选条件丢失求助
解决@material-table/core操作后筛选条件丢失的问题
问题根源
筛选条件丢失的核心原因有两点:
- 表格
data状态更新时,material-table会默认重置内部筛选状态 - 增删改操作后调用
props.getSoftwares()触发父组件更新,进而通过useEffect全量替换data,导致表格完全重新渲染,丢失已设置的筛选条件
修复步骤
1. 手动保存并绑定筛选状态
material-table提供了onFilterChange回调用于捕获当前筛选条件,我们需要将其存入组件状态,再通过filters属性手动传入表格,强制保持筛选状态:
首先添加状态变量:
const [tableFilters, setTableFilters] = useState([]);
然后给MaterialTable组件添加两个属性:
<MaterialTable // ...其他已有属性 filters={tableFilters} onFilterChange={(newFilters) => setTableFilters(newFilters)} // ... />
2. 优化数据初始化逻辑
原useEffect会在props.techstacks变化时直接全量替换data,导致表格重新初始化。改为仅在组件挂载时初始化数据:
// 替换原useEffect useEffect(() => { if (data.length === 0) { setData(props.techstacks); } }, [props.techstacks, data.length]);
3. 调整本地数据更新方式
使用函数式更新修改data状态,避免闭包导致的旧数据问题,同时保证更新后表格不会丢失筛选:
- onRowAdd修改:
setData(prevData => [...prevData, { id: response.data.id, ...newRow }]);
(注意:用接口返回的真实id替代随机生成的id,避免后续操作出错)
- onRowDelete修改:
setData(prevData => prevData.filter(row => row.id !== selectedRow.id));
- onRowUpdate修改:
setData(prevData => prevData.map(row => row.id === oldRow.id ? updatedRow : row));
关键修改后的完整代码片段
function EditTable(props) { const [data, setData] = useState(props.techstacks); const [filter, setFilter] = useState(true); const [year, setYear] = useState("all"); const [newSoftwareID, setNewSoftwareID] = useState(0); const [openMultiEdit, setOpenMultiEdit] = useState(false); const [selectedToEdit, setSelectedToEdit] = useState([]); // 新增:保存筛选状态 const [tableFilters, setTableFilters] = useState([]); function set_new_software(props) { console.log(props.newValue.id); } // ...columns定义保持不变 const handleChange = () => { setFilter(!filter); }; const closeMultiEdit = (newValue) => { setOpenMultiEdit(newValue); }; // 修改后的初始化逻辑 useEffect(() => { if (data.length === 0) { setData(props.techstacks); } }, [props.techstacks, data.length]); return ( <div className="App"> <Container maxWidth="lg"> <MaterialTable title="Techstack Data" data={data} columns={columns} // 绑定筛选状态 filters={tableFilters} onFilterChange={(newFilters) => setTableFilters(newFilters)} editable={{ onRowAdd: (newRow) => new Promise((resolve, reject) => { axios .post( `${process.env.REACT_APP_API_URL}/api/techstacks/`, { techstack_product: props.current_product, app_componenet_name: newRow.app_componenet_name, techstack_category: newRow.techstack_category, techstack_software: newRow.techstack_software, container_source: newRow.container_source, roadmap: newRow.roadmap, EA_comments: newRow.EA_comments, PA_comments: newRow.PA_comments, }, { headers: { Accept: "application/json" }, } ) .then(function (response) { // 函数式更新数据 setData(prevData => [...prevData, { id: response.data.id, ...newRow }]); }) .catch(function (error) { alert(error); reject(error); }) .finally(function (response) { props.getSoftwares(); resolve(); }); }), onRowDelete: (selectedRow) => new Promise((resolve, reject) => { axios .delete( `${process.env.REACT_APP_API_URL}/api/techstacks/${selectedRow.id}/`, { headers: { Accept: "application/json" }, } ) .then(function (response) { // 函数式更新数据 setData(prevData => prevData.filter(row => row.id !== selectedRow.id)); }) .catch(function (error) { alert(error); reject(error); }) .finally(function (response) { props.getSoftwares(); resolve(); }); }), onRowUpdate: (updatedRow, oldRow) => new Promise((resolve, reject) => { axios .patch( `${process.env.REACT_APP_API_URL}/api/techstacks/${updatedRow.id}/`, { techstack_category: updatedRow.techstack_category, app_componenet_name: updatedRow.app_componenet_name, techstack_software: updatedRow.techstack_software, container_source: updatedRow.container_source, roadmap: updatedRow.roadmap, EA_comments: updatedRow.EA_comments, PA_comments: updatedRow.PA_comments, }, { headers: { Accept: "application/json" }, } ) .then(function (response) { // 函数式更新数据 setData(prevData => prevData.map(row => row.id === oldRow.id ? updatedRow : row)); }) .catch(function (error) { alert(error); reject(error); }) .finally(function (response) { props.getSoftwares(); resolve(); }); }), }} options={{ filtering: filter, addRowPosition: "first", selection: true, pageSize: 10, pageSizeOptions: [5, 10, 25, 50, 100], paging: true, grouping: true, }} actions={[ { tooltip: "Remove All Selected Items", icon: "delete", onClick: (evt, data) => { const to_delete = []; for (const item in data) { to_delete.push(data[item].id); } alert(`You want to delete ${data.length} rows.`); const axiosArray = []; for (let x = 0; x < to_delete.length; x++) { const newPromise = axios.delete( `${process.env.REACT_APP_API_URL}/api/techstacks/${to_delete[x]}/`, { headers: { Accept: "application/json" }, } ); axiosArray.push(newPromise); } axios .all(axiosArray) .then( axios.spread((...responses) => { responses.forEach((res) => console.log("Success")); console.log("submitted all axios calls"); }) ) .catch((error) => {}) .finally(function (response) { props.getSoftwares(); }); }, }, ]} /> </Container> </div> ); } export default EditTable;
额外提示
- 禁止用随机数生成行id,必须使用接口返回的真实唯一id,避免后续更新、删除操作出现匹配错误
props.getSoftwares()触发的父组件数据更新,不会再覆盖本地已修改的data状态,保证筛选条件持续生效
内容的提问来源于stack exchange,提问作者fierychizza1
相关产品推荐
相关产品推荐

