在这里以react、shadcn为例,此处例子展示的特定情况为:删除按钮
disabled+useState禁用
以下代码的设置可以保证按钮点击后立即禁用
const [isRemoving,setIsRemoving] = useState(false);
<AlertDialogAction
disabled={isRemoving}//默认可点击
onClick={(e) => {
e.stopPropagation();//禁止冒泡
setIsRemoving(true);//立即禁止点击
remove({ id: documentId }).finally(() => {
setIsRemoving(false);
});
}}
>
Delete
</AlertDialogAction>;
对比节流方案
const DeleteAction = () => {
const isThrottled = useRef(false);
const handleDelete = () => {
if (isThrottled.current) return;
isThrottled.current = true;
remove({ id: documentId });
setTimeout(() => {
isThrottled.current = false;
}, 1000);
};
return (
<AlertDialogAction onClick={handleDelete}>
Delete
</AlertDialogAction>
);
};
对比防抖方案
const DeleteAction = () => {
const timerRef = useRef<NodeJS.Timeout>();
const handleDelete = () => {
// 清除之前的定时器
if (timerRef.current) {
clearTimeout(timerRef.current);
}
// 设置新的定时器
timerRef.current = setTimeout(() => {
remove({ id: documentId });
}, 1000);
};
// 组件卸载时清理定时器
useEffect(() => {
return () => {
if (timerRef.current) {
clearTimeout(timerRef.current);
}
};
}, []);
return (
<AlertDialogAction onClick={handleDelete}>
Delete
</AlertDialogAction>
);
};
为什么不选择节流防抖
由以上代码可以看出明显是第一种方案的代码量少性能更优方便阅读和维护,并且删除按钮每次有且仅需要点击一次不需要多次点击,所以使用节流防抖有点“画蛇添足”,这里只是以删除按钮为例,不仅限于删除按钮情况,可在写代码之时留意一下是否“有必要”使用节流防抖函数。
再者像节流防抖这类易实现的函数推荐手写而不使用库函数,为什么现在支持Tree Shaking按需引入还需要手写?因为可以根据实际情况高度定制和简化代码(体积更小)以及性能优化,当然手写不易实现的功能还是需要使用第三方库,所以我推荐采用混合策略:核心路径代码手写优化 + 复杂功能使用高质量小型库。