You've already forked Nano-Banana-AI-Image-Editor
修复(ui): 解决Toast通知不正常关闭的问题
- 修复Toast组件中鼠标悬停状态的延迟通知逻辑 - 重构ToastContext中的定时器管理机制,防止内存泄漏 - 优化Toast的hover状态同步,确保定时器正确暂停和恢复 - 增强cleanup机制,清理已删除Toast的残留定时器 - 解决Toast在指定时间后不自动关闭的问题 修复内容: - Toast.tsx: 移除鼠标离开后的1秒延迟,立即通知状态变化 - ToastContext.tsx: 改进定时器生命周期管理和清理逻辑 验证: - 构建成功通过 - 所有测试套件通过(34个测试) - Toast现在能正确按时关闭,悬停暂停功能正常
This commit is contained in:
@@ -42,10 +42,8 @@ export const Toast: React.FC<ToastProps> = ({ id, message, type, details, onClos
|
||||
};
|
||||
|
||||
const handleMouseLeave = () => {
|
||||
// Set a timeout to mark as not hovered after 1 second
|
||||
hoverTimeoutRef.current = setTimeout(() => {
|
||||
onHoverChange?.(false);
|
||||
}, 1000);
|
||||
// Immediately mark as not hovered
|
||||
onHoverChange?.(false);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
|
||||
@@ -50,6 +50,11 @@ export const ToastProvider: React.FC<{ children: React.ReactNode }> = ({ childre
|
||||
};
|
||||
|
||||
const removeToast = (id: string) => {
|
||||
// Clear any existing timeout for this toast
|
||||
if (hoverTimeouts.current[id]) {
|
||||
clearTimeout(hoverTimeouts.current[id]);
|
||||
delete hoverTimeouts.current[id];
|
||||
}
|
||||
dispatch({ type: 'REMOVE_TOAST', payload: id });
|
||||
};
|
||||
|
||||
@@ -59,21 +64,24 @@ export const ToastProvider: React.FC<{ children: React.ReactNode }> = ({ childre
|
||||
|
||||
// Auto remove toasts after duration, but respect hover state
|
||||
useEffect(() => {
|
||||
const timers = toasts.map(toast => {
|
||||
// Create a copy of current timeouts to track which ones we need to clear
|
||||
const currentTimeouts = { ...hoverTimeouts.current };
|
||||
|
||||
toasts.forEach(toast => {
|
||||
// Clear any existing timeout for this toast
|
||||
if (hoverTimeouts.current[toast.id]) {
|
||||
clearTimeout(hoverTimeouts.current[toast.id]);
|
||||
delete hoverTimeouts.current[toast.id];
|
||||
if (currentTimeouts[toast.id]) {
|
||||
clearTimeout(currentTimeouts[toast.id]);
|
||||
delete currentTimeouts[toast.id];
|
||||
}
|
||||
|
||||
// If toast is hovered, don't set a timer
|
||||
if (toast.hovered) {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
// If duration is 0, it's persistent
|
||||
if (toast.duration === 0) {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
// Set timeout to remove toast
|
||||
@@ -81,14 +89,23 @@ export const ToastProvider: React.FC<{ children: React.ReactNode }> = ({ childre
|
||||
removeToast(toast.id);
|
||||
}, toast.duration);
|
||||
|
||||
return { id: toast.id, timeout };
|
||||
hoverTimeouts.current[toast.id] = timeout;
|
||||
});
|
||||
|
||||
// Cleanup function
|
||||
// Clear any remaining timeouts for toasts that no longer exist
|
||||
Object.entries(currentTimeouts).forEach(([id, timeout]) => {
|
||||
clearTimeout(timeout);
|
||||
delete hoverTimeouts.current[id];
|
||||
});
|
||||
|
||||
// Cleanup function for when component unmounts or toasts change
|
||||
return () => {
|
||||
timers.forEach(timer => {
|
||||
if (timer) clearTimeout(timer.timeout);
|
||||
// Clear all active timeouts
|
||||
Object.values(hoverTimeouts.current).forEach(timeout => {
|
||||
clearTimeout(timeout);
|
||||
});
|
||||
// Reset the timeouts object
|
||||
hoverTimeouts.current = {};
|
||||
};
|
||||
}, [toasts]);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user