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

MUI X Data Grid:修复验证通过时点击外部仍恢复原值的问题

MUI X Data Grid邮箱验证恢复原值问题修复

问题描述

我在MUI X Data Grid里做邮箱字段验证,目前验证功能正常,但只有按Esc键时,验证失败的单元格才会恢复原值。参考MUI官方验证示例(验证失败显示Tooltip提示)修改后,我尝试用onBlur和stopCellEditMode实现:验证失败且点击单元格外部时恢复原值,但现在有个新问题——就算邮箱验证通过,点击外部也会把内容恢复成原值;删掉handleBadEmail函数就能正常保存邮箱内容。

现有代码

let promiseTimeout;
const validateEmail = (email) => {
  return new Promise((resolve) => {
    promiseTimeout = setTimeout(() => {
      let emailWorks = false;
      if (
        String(email)
          .toLowerCase()
          .match(
            /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
          )
      ) {
        emailWorks = true;
      }
      resolve(emailWorks ? null : `${email} is not a valid email.`);
    }, Math.random() * 500 + 100); // 模拟网络延迟
  });
};

const StyledTooltip = styled(({ className, ...props }) => (
  <Tooltip {...props} classes={{ popper: className }} />
))(({ theme }) => ({
  [`& .${tooltipClasses.tooltip}`]: {
    backgroundColor: theme.palette.error.main,
    color: theme.palette.error.contrastText,
  },
}));

function NameEditInputCell(props) {
  
  const { error, value } = props;
  const apiRef = useGridApiContext();

  const handleBadEmail = async () => {
    let oldValue = apiRef.current.setEditCellValue({
      id: props.id,
      field: "email",
      value: value,
    });

    if (error) {
      apiRef.current.stopCellEditMode({
        id: props.id,
        field: "email",
        value: oldValue,
        ignoreModifications: false,
      });
    }
  };

  return (
    <StyledTooltip open={!!error} title={error}>
      <GridEditInputCell onBlur={handleBadEmail} {...props} />
    </StyledTooltip>
  );
}

function renderEditName(params) {
  return <NameEditInputCell {...params} />;
}

const ColDefs = () => {
  const preProcessEditCellProps = async (params) => {
    const errorMessage = await validateEmail(params.props.value.toString());
    return { ...params.props, error: errorMessage };
  };

  return {
    columns: [
      {
        field: "col1",
        headerName: "Seller",
        flex: 1,
        editable: true,
      },
      {
        field: "email",
        headerName: "Email",
        flex: 1,
        editable: true,
        preProcessEditCellProps,
        renderEditCell: renderEditName,
      },
    ]
  };
}

问题原因与修复方案

问题根源

handleBadEmail函数开头调用的setEditCellValue会强制把单元格值设为初始的value,这就导致不管验证是否通过,用户输入的内容都会被提前覆盖,后续的error判断完全失效。

修复代码

修正NameEditInputCell的逻辑,只有验证失败时才恢复原值:

function NameEditInputCell(props) {
  const { error, id, field, value: initialValue } = props;
  const apiRef = useGridApiContext();

  const handleBadEmail = () => {
    // 仅当验证失败时,恢复到编辑前的初始值
    if (error) {
      apiRef.current.stopCellEditMode({
        id,
        field,
        value: initialValue,
        // 忽略当前修改,直接恢复初始状态
        ignoreModifications: true,
      });
    }
  };

  return (
    <StyledTooltip open={!!error} title={error}>
      <GridEditInputCell onBlur={handleBadEmail} {...props} />
    </StyledTooltip>
  );
}

额外优化:清理定时器避免内存泄漏

在使用validateEmail的组件中添加清理逻辑,防止组件卸载后定时器仍在运行:

import { useEffect } from 'react';

// ... 其他代码 ...

const YourDataGridComponent = () => {
  useEffect(() => {
    return () => {
      if (promiseTimeout) {
        clearTimeout(promiseTimeout);
      }
    };
  }, []);

  // ... 渲染DataGrid的逻辑 ...
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 07:31:17