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

React删除按钮点击后未禁用、无法防止重复点击的问题排查

问题原因

  • 如果你把const [disabled, setDisabled] = useState(false)写在了linkFollow函数内部,这个函数是表格的单元格渲染回调,每次组件重新渲染都会重新执行linkFollow,状态会被重置为初始值false。你点击按钮触发setDisabled(true)之后会引发组件重渲染,linkFollow重新执行时disabled又变回false,自然看不到禁用效果。
  • 如果你是渲染多行列表的删除按钮,用单一的布尔值disabled会导致点击一个按钮后所有行的删除按钮都被禁用,不符合交互逻辑。

修复方案

多行列场景(大多数表格删除的情况)

把状态提到组件顶层,用Set存储已经触发删除操作的行唯一标识(示例用appName作为唯一标识,你可以换成实际的行ID字段):

// 组件顶层作用域,不要放在linkFollow内部
const [deletedRowKeys, setDeletedRowKeys] = useState(new Set());

const linkFollow = (cell, row, rowIndex, formatExtraData) => {
  const isCurrentRowDisabled = deletedRowKeys.has(row.appName);
  return (
    <Button
      disabled={isCurrentRowDisabled}
      onClick={(event) => { 
        event.preventDefault();
        // 先标记当前行禁用,避免重复点击
        setDeletedRowKeys(prev => new Set(prev).add(row.appName));
        console.log(row.appName)
        
        axios.post("https://add", {
          data: {
            appName: row.appName,
            action: "delete"
          },
        })
        .then(function (response) {
          toast.success("deleted successfully", {
            position: toast.POSITION.TOP_RIGHT,
            hideProgressBar: true,
          });
          setlength(false);
          // 若删除成功后该行会从列表移除,不需要额外重置状态;若需要保留行可恢复按钮,可删除下面注释的代码
          /*
          setDeletedRowKeys(prev => {
            const newSet = new Set(prev);
            newSet.delete(row.appName);
            return newSet;
          })
          */
        })
        .catch(function (error) {
          toast.error("deletion failed", {
            position: "top-right",
            autoClose: 5000,
            hideProgressBar: true,
          });
          console.log(error);
          // 请求失败后重置当前行的禁用状态,允许用户重新操作
          setDeletedRowKeys(prev => {
            const newSet = new Set(prev);
            newSet.delete(row.appName);
            return newSet;
          })
        });
      }}
    >
      delete
    </Button>
  )
}

单按钮场景(全局只有一个删除按钮)

直接把disabled状态移到组件顶层即可,同时补充失败后的状态重置逻辑:

// 组件顶层作用域
const [disabled, setDisabled] = useState(false);

const linkFollow = (cell, row, rowIndex, formatExtraData) => {
  return (
    <Button
      disabled={disabled}
      onClick={(event) => { 
        event.preventDefault();
        setDisabled(true);
        console.log(row.appName)
        
        axios.post("https://add", {
          data: {
            appName: row.appName,
            action: "delete"
          },
        })
        .then(function (response) {
          toast.success("deleted successfully", {
            position: toast.POSITION.TOP_RIGHT,
            hideProgressBar: true,
          });
          setlength(false);
          // 按需决定是否恢复按钮可用
          // setDisabled(false);
        })
        .catch(function (error) {
          toast.error("deletion failed", {
            position: "top-right",
            autoClose: 5000,
            hideProgressBar: true,
          });
          console.log(error);
          // 请求失败恢复按钮可用
          setDisabled(false);
        });
      }}
    >
      delete
    </Button>
  )
}

额外提示:你原代码中的请求地址https:/add缺少一个斜杠,已在上述代码中修正,另外原代码catch回调中删除失败的提示误用了toast.success,上述代码也同步改为toast.error更符合交互逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 13:24:08