如何配置Toastify使其仅在指定时间前5分钟显示一次?
解决Toastify仅在指定时间前5分钟显示一次的问题
原代码的核心问题
currentTime在useEffect初始化时就固定了,后续定时器循环里一直用这个旧时间做判断,一旦时间匹配,每分钟都会触发一次通知- 没有标记toast是否已经显示过,关闭后会被重复触发
优化方案
通过记录toast显示状态+精准定时触发+及时清理定时器可以解决问题,具体修改如下:
import { useState, useEffect } from 'react'; import { toast, ToastContainer } from 'react-toastify'; import { InfoOutlinedIcon } from '@mui/icons-material'; import 'react-toastify/dist/ReactToastify.css'; export default function App() { const [time, setTime] = useState(null); // 新增状态:标记toast是否已经显示过 const [hasShownToast, setHasShownToast] = useState(false); useEffect(() => { const targetTime = new Date(2022, 11, 20, 11, 7); // 注意:月份从0开始,11代表12月 const reminderTime = new Date(targetTime - 5 * 60000); const currentTime = new Date(); // 页面刷新时,如果已过提醒时间或toast已显示,直接退出逻辑 if (currentTime > reminderTime || hasShownToast) { return; } // 计算距离提醒时间的毫秒数,用setTimeout实现精准单次触发 const timeUntilReminder = reminderTime - currentTime; const reminderTimeout = setTimeout(() => { if (!hasShownToast) { notify(); setHasShownToast(true); // 标记为已显示,避免重复触发 } }, timeUntilReminder); // 实时更新当前时间的定时器 const timeUpdateInterval = setInterval(() => { setTime(new Date()); }, 1000); // 清理所有定时器,避免内存泄漏 return () => { clearTimeout(reminderTimeout); clearInterval(timeUpdateInterval); }; }, [hasShownToast]); // 依赖hasShownToast,状态变化时重新校验逻辑 const notify = () => toast(customMsg, { icon: <InfoOutlinedIcon />, autoClose: false, closeOnClick: false }); const customMsg = () => ( <div> Hello Toaster Test <div>123</div> </div> ); return ( <div> <div>{time ? time.toString() : "Loading"}</div> <ToastContainer limit={1} /> </div> ); }
关键修改说明
- 用
setTimeout替代setInterval:直接计算距离提醒时间的间隔,到点触发一次就结束,彻底避免循环触发的问题 - 新增
hasShownToast状态:标记toast是否已显示,即使页面刷新,只要状态未重置就不会重复弹出(如果需要持久化,可搭配localStorage) - 前置时间校验:初始化时先判断当前时间是否已过提醒节点,避免页面刷新后在过期时间后仍触发通知
- 完整清理定时器:在
useEffect的清理函数中同时清理提醒定时器和时间更新定时器,避免内存泄漏
内容的提问来源于stack exchange,提问作者FishyK
相关产品推荐
相关产品推荐

