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

如何在react-hot-toast中实现支持悬停暂停的倒计时功能

实现react-hot-toast悬停暂停倒计时方案

你可以直接通过自定义Toast组件+原生计时器逻辑实现需求,无需额外依赖第三方倒计时库,核心逻辑用useRef存储计时相关变量避免React重渲染导致的计时错乱问题,具体实现如下:

核心实现逻辑

用useRef存储倒计时剩余时长、计时器ID、暂停状态三个变量,鼠标进入时清除计时器并记录当前剩余时长,鼠标移出时从剩余时长断点重启倒计时,倒计时结束后手动调用toast.dismiss关闭弹窗即可。

完整可运行代码示例

import { useState, useEffect, useRef } from 'react';
import toast, { Toaster } from 'react-hot-toast';

// 自定义带倒计时的Toast组件
const CountdownToast = ({ id, totalDuration = 5000 }) => {
  // 计时相关变量用useRef存储,避免重渲染导致的闭包问题
  const remainingTimeRef = useRef(totalDuration);
  const timerRef = useRef(null);
  const isPausedRef = useRef(false);
  const [showSecond, setShowSecond] = useState(totalDuration / 1000);

  // 启动/恢复倒计时方法
  const startCountdown = (duration) => {
    if (timerRef.current) clearInterval(timerRef.current);
    const startTime = Date.now();
    timerRef.current = setInterval(() => {
      if (isPausedRef.current) return;
      const elapsedTime = Date.now() - startTime;
      const leftTime = duration - elapsedTime;
      // 倒计时结束关闭弹窗
      if (leftTime <= 0) {
        clearInterval(timerRef.current);
        toast.dismiss(id);
        return;
      }
      remainingTimeRef.current = leftTime;
      setShowSecond(Math.ceil(leftTime / 1000));
    }, 100);
  };

  // 组件挂载启动倒计时
  useEffect(() => {
    startCountdown(totalDuration);
    return () => clearInterval(timerRef.current);
  }, []);

  // 鼠标进入暂停倒计时
  const handlePause = () => {
    isPausedRef.current = true;
    if (timerRef.current) clearInterval(timerRef.current);
  };

  // 鼠标移出恢复倒计时
  const handleResume = () => {
    isPausedRef.current = false;
    startCountdown(remainingTimeRef.current);
  };

  return (
    <div 
      onMouseEnter={handlePause}
      onMouseLeave={handleResume}
      style={{ 
        padding: '12px 16px', 
        background: '#fff', 
        borderRadius: '6px', 
        boxShadow: '0 2px 10px rgba(0,0,0,0.12)' 
      }}
    >
      操作成功,{showSecond}秒后自动关闭
    </div>
  );
};

// 业务组件调用示例
function App() {
  const triggerToast = () => {
    toast.custom((t) => <CountdownToast id={t.id} totalDuration={5000} />);
  };

  return (
    <div style={{ padding: '20px' }}>
      <button onClick={triggerToast}>弹出倒计时提示</button>
      <Toaster />
    </div>
  );
}

export default App;

注意事项

  • 核心计时变量不要用useState存储,频繁触发重渲染不仅会增加性能损耗,还容易出现闭包导致的计时不准问题
  • 所有逻辑都封装在自定义Toast组件内部,不需要修改react-hot-toast全局配置,不会影响项目内其他普通Toast的正常使用
  • 如果需要实现进度条样式的倒计时效果,直接通过remainingTimeRef.current / totalDuration计算进度比例即可快速实现

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 21:09:03