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

React实现点击删除按钮后10秒内切换撤销按钮的方法

实现方案

核心逻辑是把「立即删除」改成「延迟确认删除」,拆分几个步骤做就行:

  • 给每个列表项增加待删除标记、剩余倒计时字段,不要点击删除就直接把数据从列表移除
  • 点击删除时只标记对应条目为待删除状态,启动10秒倒计时,倒计时期间条目保留在列表里,按钮切换为撤销按钮
  • 倒计时每秒更新剩余时长,归零时才真正执行数据删除逻辑,同时清除定时器
  • 点击撤销按钮时,清除对应条目的定时器,移除待删除标记,终止删除流程
  • 所有定时器要在组件卸载、条目被删除/撤销时及时清理,避免内存泄漏

核心改造代码
import { useState, useRef, useEffect } from 'react'
import Checkbox from './Checkbox' // 项目原有Checkbox组件

function App() {
  const [items, setItems] = useState([]) // 原有items状态
  // 用ref存储所有定时器id,避免重复创建、方便统一清理
  const timerRef = useRef({})

  // 组件卸载时清掉所有残留定时器
  useEffect(() => {
    return () => {
      Object.values(timerRef.current).forEach(clearInterval)
    }
  }, [])

  // 改后的删除触发方法:不直接删,先标记待删除
  const triggerDelete = (itemId) => {
    // 标记对应条目为待删除,初始化10秒倒计时
    setItems(prev => prev.map(item => {
      if (item.id === itemId) {
        return { ...item, isPendingDelete: true, countdown: 10 }
      }
      return item
    }))

    // 启动倒计时定时器
    timerRef.current[itemId] = setInterval(() => {
      setItems(prev => {
        const target = prev.find(item => item.id === itemId)
        // 找不到条目说明已经被处理,直接清定时器
        if (!target) {
          clearInterval(timerRef.current[itemId])
          delete timerRef.current[itemId]
          return prev
        }
        // 倒计时归零,执行真正删除
        if (target.countdown <= 1) {
          clearInterval(timerRef.current[itemId])
          delete timerRef.current[itemId]
          return prev.filter(item => item.id !== itemId)
        }
        // 倒计时减1秒
        return prev.map(item => {
          if (item.id === itemId) {
            return { ...item, countdown: item.countdown - 1 }
          }
          return item
        })
      })
    }, 1000)
  }

  // 撤销删除方法
  const undoDelete = (itemId) => {
    // 清掉对应定时器
    clearInterval(timerRef.current[itemId])
    delete timerRef.current[itemId]
    // 移除待删除标记
    setItems(prev => prev.map(item => {
      if (item.id === itemId) {
        return { ...item, isPendingDelete: false, countdown: 0 }
      }
      return item
    }))
  }

  // 原有勾选逻辑
  const onChangeBox = (targetItem) => {
    setItems(prev => prev.map(item => {
      if (item.id === targetItem.id) {
        return { ...item, done: !item.done }
      }
      return item
    }))
  }

  return (
    <div>
      <ul>
        {items.map((item) => {
          return (
            <li
              key={item.id}
              style={{ 
                textDecoration: item.done ? "line-through" : null,
                opacity: item.isPendingDelete ? 0.5 : 1 // 待删除条目加半透明提示
              }}
            >
              <Checkbox
                onClick={() => onChangeBox(item)}
                defaultChecked={item.done}
                disabled={item.isPendingDelete} // 待删除时禁用勾选,避免交互冲突
              />
              {item.value}{" "}
              {
                item.isPendingDelete ? (
                  <button
                    className="undo-button"
                    onClick={() => undoDelete(item.id)}
                  >
                    撤销删除({item.countdown}s)
                  </button>
                ) : (
                  <button
                    className="del-button"
                    onClick={() => triggerDelete(item.id)}
                  >
                    ❌
                  </button>
                )
              }
            </li>
          );
        })}
      </ul>
    </div>
  );
}

export default App;

可选优化点
  • 待删除的条目可以加红色边框、浅红背景等更明显的视觉提示
  • 倒计时最后3秒可以把数字标红,强化用户感知
  • 这套逻辑天然支持多条目同时触发删除,每个条目独立维护自己的定时器和倒计时,不会互相干扰

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 19:03:41