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

material-table中onRowAdd/onRowUpdate后筛选条件丢失求助

解决@material-table/core操作后筛选条件丢失的问题

问题根源

筛选条件丢失的核心原因有两点:

  1. 表格data状态更新时,material-table会默认重置内部筛选状态
  2. 增删改操作后调用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 02:24:13