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
相关产品推荐
相关产品推荐

