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

MUI X DataGrid编辑删除按钮异常:基础版无法进入行编辑模式

MUI DataGrid基础版行编辑不生效的解决方案

问题根源

MUI的DataGrid(基础版)仅支持单元格级编辑,不提供DataGridPro专属的整行编辑模式。你复制的Pro版代码中使用了editMode="row"、rowModesModel等Pro版独有的API,基础版无法识别这些配置,因此点击编辑按钮后仅切换了操作按钮,单元格并未进入编辑状态。

两种解决方案

方案1:改用DataGridPro(推荐,若项目允许)

如果你的项目可以引入Pro版依赖,直接将DataGrid换回DataGridPro,现有代码就能正常运行,无需额外修改。

方案2:基于DataGrid基础版实现模拟行编辑

如果必须使用基础版,需要手动控制单元格的编辑状态,模拟整行编辑的效果。以下是修改后的代码:

import * as React from "react";
import PropTypes from "prop-types";
import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
import AddIcon from "@mui/icons-material/Add";
import EditIcon from "@mui/icons-material/Edit";
import DeleteIcon from "@mui/icons-material/DeleteOutlined";
import SaveIcon from "@mui/icons-material/Save";
import CancelIcon from "@mui/icons-material/Close";
import {
  GridCellModes,
  DataGrid,
  GridToolbarContainer,
  GridActionsCellItem,
} from "@mui/x-data-grid";
import {
  randomCreatedDate,
  randomTraderName,
  randomUpdatedDate,
  randomId,
} from "@mui/x-data-grid-generator";

const initialRows = [
  {
    id: randomId(),
    name: randomTraderName(),
    age: 25,
    dateCreated: randomCreatedDate(),
    lastLogin: randomUpdatedDate(),
  },
  {
    id: randomId(),
    name: randomTraderName(),
    age: 36,
    dateCreated: randomCreatedDate(),
    lastLogin: randomUpdatedDate(),
  },
  {
    id: randomId(),
    name: randomTraderName(),
    age: 19,
    dateCreated: randomCreatedDate(),
    lastLogin: randomUpdatedDate(),
  },
  {
    id: randomId(),
    name: randomTraderName(),
    age: 28,
    dateCreated: randomCreatedDate(),
    lastLogin: randomUpdatedDate(),
  },
  {
    id: randomId(),
    name: randomTraderName(),
    age: 23,
    dateCreated: randomCreatedDate(),
    lastLogin: randomUpdatedDate(),
  },
];

function EditToolbar(props) {
  const { setRows, setCellModesModel } = props;

  const handleClick = () => {
    const id = randomId();
    const newRow = { id, name: "", age: "", dateCreated: new Date(), lastLogin: new Date(), isNew: true };
    setRows((oldRows) => [...oldRows, newRow]);
    
    // 新行直接进入编辑状态
    const cellModes = {};
    ["name", "age", "dateCreated", "lastLogin"].forEach(field => {
      cellModes[`${id}-${field}`] = { mode: GridCellModes.Edit };
    });
    setCellModesModel(prev => ({ ...prev, ...cellModes }));
  };

  return (
    <GridToolbarContainer>
      <Button color="primary" startIcon={<AddIcon />} onClick={handleClick}>
        Add record
      </Button>
    </GridToolbarContainer>
  );
}

EditToolbar.propTypes = {
  setCellModesModel: PropTypes.func.isRequired,
  setRows: PropTypes.func.isRequired,
};

export default function FullFeaturedCrudGrid() {
  const [rows, setRows] = React.useState(initialRows);
  const [cellModesModel, setCellModesModel] = React.useState({});

  const handleEditClick = (id) => () => {
    // 将该行所有可编辑字段设为编辑状态
    const newCellModes = {};
    ["name", "age", "dateCreated", "lastLogin"].forEach(field => {
      newCellModes[`${id}-${field}`] = { mode: GridCellModes.Edit };
    });
    setCellModesModel(prev => ({ ...prev, ...newCellModes }));
  };

  const handleSaveClick = (id) => () => {
    // 将该行所有字段设为查看状态
    const newCellModes = {};
    ["name", "age", "dateCreated", "lastLogin"].forEach(field => {
      newCellModes[`${id}-${field}`] = { mode: GridCellModes.View };
    });
    setCellModesModel(prev => ({ ...prev, ...newCellModes }));

    // 标记新行已保存
    setRows(prev => prev.map(row => 
      row.id === id ? { ...row, isNew: false } : row
    ));
  };

  const handleDeleteClick = (id) => () => {
    setRows(rows.filter((row) => row.id !== id));
    // 清除该行的编辑状态记录
    const newCellModes = { ...cellModesModel };
    ["name", "age", "dateCreated", "lastLogin"].forEach(field => {
      delete newCellModes[`${id}-${field}`];
    });
    setCellModesModel(newCellModes);
  };

  const handleCancelClick = (id) => () => {
    // 将该行所有字段设为查看状态
    const newCellModes = {};
    ["name", "age", "dateCreated", "lastLogin"].forEach(field => {
      newCellModes[`${id}-${field}`] = { mode: GridCellModes.View, ignoreModifications: true };
    });
    setCellModesModel(prev => ({ ...prev, ...newCellModes }));

    // 删除未保存的新行
    const editedRow = rows.find((row) => row.id === id);
    if (editedRow.isNew) {
      setRows(rows.filter((row) => row.id !== id));
    }
  };

  const processRowUpdate = (newRow) => {
    const updatedRow = { ...newRow, isNew: false };
    setRows(rows.map((row) => (row.id === newRow.id ? updatedRow : row)));
    return updatedRow;
  };

  const columns = [
    { field: "name", headerName: "Name", width: 180, editable: true },
    { field: "age", headerName: "Age", type: "number", editable: true },
    {
      field: "dateCreated",
      headerName: "Date Created",
      type: "date",
      width: 180,
      editable: true,
    },
    {
      field: "lastLogin",
      headerName: "Last Login",
      type: "dateTime",
      width: 220,
      editable: true,
    },
    {
      field: "actions",
      type: "actions",
      headerName: "Actions",
      width: 100,
      cellClassName: "actions",
      getActions: ({ id }) => {
        // 判断该行是否有任意单元格处于编辑状态
        const isInEditMode = ["name", "age", "dateCreated", "lastLogin"].some(field => 
          cellModesModel[`${id}-${field}`]?.mode === GridCellModes.Edit
        );

        if (isInEditMode) {
          return [
            <GridActionsCellItem
              icon={<SaveIcon />}
              label="Save"
              onClick={handleSaveClick(id)}
            />,
            <GridActionsCellItem
              icon={<CancelIcon />}
              label="Cancel"
              className="textPrimary"
              onClick={handleCancelClick(id)}
              color="inherit"
            />,
          ];
        }

        return [
          <GridActionsCellItem
            icon={<EditIcon />}
            label="Edit"
            className="textPrimary"
            onClick={handleEditClick(id)}
            color="inherit"
          />,
          <GridActionsCellItem
            icon={<DeleteIcon />}
            label="Delete"
            onClick={handleDeleteClick(id)}
            color="inherit"
          />,
        ];
      },
    },
  ];

  return (
    <Box
      sx={{
        height: 500,
        width: "100%",
        "& .actions": {
          color: "text.secondary",
        },
        "& .textPrimary": {
          color: "text.primary",
        },
      }}
    >
      <DataGrid
        rows={rows}
        columns={columns}
        cellModesModel={cellModesModel}
        onCellModesModelChange={(newModel) => setCellModesModel(newModel)}
        processRowUpdate={processRowUpdate}
        slots={{
          toolbar: EditToolbar,
        }}
        slotProps={{
          toolbar: { setRows, setCellModesModel },
        }}
      />
    </Box>
  );
}

关键修改说明

  • 移除了editMode="row"、rowModesModel等Pro版专属属性,改用基础版支持的cellModesModel控制单个单元格的编辑状态
  • 点击编辑按钮时,批量将该行所有可编辑字段设为编辑模式
  • 通过判断该行任意单元格的编辑状态,切换操作按钮的显示
  • 调整新增行的逻辑,直接将新行的所有可编辑字段设为编辑状态

内容的提问来源于stack exchange,提问作者jm2002

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 00:42:50