MUI Snackbar的autoHideDuration在页面失焦时暂停的问题咨询
MUI Snackbar autoHideDuration 页面失焦时暂停的问题解析与解决办法
原因说明
这并非无法避免的副作用,而是浏览器的性能优化特性导致的。MUI Snackbar的自动隐藏逻辑依赖浏览器的requestAnimationFrame API,而Chrome、Firefox等现代浏览器在页面失焦(切换到其他标签页)时,会暂停requestAnimationFrame的回调执行以节省系统资源,这就导致Snackbar的计时停滞,直到页面重新获得焦点才继续倒计时。
解决办法
方法一:自定义setTimeout计时替代MUI内置逻辑
绕过MUI自带的autoHideDuration,自己通过setTimeout控制Snackbar的显示时长。setTimeout在页面失焦时不会完全暂停(部分浏览器可能有轻微延迟,但不会停止计时),能保证Snackbar按时隐藏。
示例代码:
import { useState } from 'react'; import Snackbar from '@mui/material/Snackbar'; import Alert from '@mui/material/Alert'; const CustomAutoHideSnackbar = ({ open, onClose, message, autoHideDuration = 3000 }) => { const [isOpen, setIsOpen] = useState(open); useState(() => { if (isOpen) { const timer = setTimeout(() => { setIsOpen(false); onClose?.(); }, autoHideDuration); return () => clearTimeout(timer); } }, [isOpen, autoHideDuration, onClose]); return ( <Snackbar open={isOpen} onClose={onClose} autoHideDuration={null} // 禁用MUI内置自动隐藏 > <Alert severity="info">{message}</Alert> </Snackbar> ); }; // 使用示例 const App = () => { const [open, setOpen] = useState(false); const handleClick = () => setOpen(true); const handleClose = () => setOpen(false); return ( <div> <button onClick={handleClick}>显示Snackbar</button> <CustomAutoHideSnackbar open={open} onClose={handleClose} message="自定义计时的Snackbar" autoHideDuration={3000} /> </div> ); }; export default App;
方法二:监听页面焦点事件补全剩余计时
如果想保留MUI的autoHideDuration逻辑,可以通过监听visibilitychange事件,记录页面失焦时已消耗的时长,重新获焦时计算剩余时间并手动触发关闭。
示例代码:
import { useState, useEffect, useRef } from 'react'; import Snackbar from '@mui/material/Snackbar'; import Alert from '@mui/material/Alert'; const FocusAwareSnackbar = ({ open, onClose, message, autoHideDuration = 3000 }) => { const [isOpen, setIsOpen] = useState(open); const startTimeRef = useRef(null); const remainingTimeRef = useRef(autoHideDuration); // 记录Snackbar打开的时间点 useEffect(() => { if (isOpen) { startTimeRef.current = Date.now(); remainingTimeRef.current = autoHideDuration; } }, [isOpen, autoHideDuration]); // 监听页面可见性变化 useEffect(() => { const handleVisibilityChange = () => { if (document.hidden) { // 失焦时计算已过时间,更新剩余时长 const elapsed = Date.now() - startTimeRef.current; remainingTimeRef.current = Math.max(0, autoHideDuration - elapsed); } else { // 获焦时如果还有剩余时间,启动定时器关闭 if (isOpen && remainingTimeRef.current > 0) { const timer = setTimeout(() => { setIsOpen(false); onClose?.(); }, remainingTimeRef.current); return () => clearTimeout(timer); } } }; document.addEventListener('visibilitychange', handleVisibilityChange); return () => document.removeEventListener('visibilitychange', handleVisibilityChange); }, [isOpen, onClose, autoHideDuration]); return ( <Snackbar open={isOpen} onClose={onClose} autoHideDuration={isOpen ? autoHideDuration : null} > <Alert severity="info">{message}</Alert> </Snackbar> ); }; // 使用示例 const App = () => { const [open, setOpen] = useState(false); const handleClick = () => setOpen(true); const handleClose = () => setOpen(false); return ( <div> <button onClick={handleClick}>显示Snackbar</button> <FocusAwareSnackbar open={open} onClose={handleClose} message="焦点感知的Snackbar" autoHideDuration={3000} /> </div> ); }; export default App;
内容的提问来源于stack exchange,提问作者Dev T
相关产品推荐
相关产品推荐

