diff --git a/src/components/GlobalErrorIndicator.tsx b/src/components/GlobalErrorIndicator.tsx index f05bb67..d0e5d14 100644 --- a/src/components/GlobalErrorIndicator.tsx +++ b/src/components/GlobalErrorIndicator.tsx @@ -1,6 +1,6 @@ 'use client'; -import { useEffect, useState } from 'react'; +import { useCallback, useEffect, useRef, useState } from 'react'; interface ErrorInfo { id: string; @@ -12,6 +12,42 @@ export function GlobalErrorIndicator() { const [currentError, setCurrentError] = useState(null); const [isVisible, setIsVisible] = useState(false); const [isReplacing, setIsReplacing] = useState(false); + const [isClosing, setIsClosing] = useState(false); + const currentErrorRef = useRef(null); + const closeTimerRef = useRef(null); + const exitTimerRef = useRef(null); + + const clearCloseTimer = useCallback(() => { + if (closeTimerRef.current !== null) { + window.clearTimeout(closeTimerRef.current); + closeTimerRef.current = null; + } + }, []); + + const clearExitTimer = useCallback(() => { + if (exitTimerRef.current !== null) { + window.clearTimeout(exitTimerRef.current); + exitTimerRef.current = null; + } + }, []); + + const handleClose = useCallback(() => { + clearCloseTimer(); + clearExitTimer(); + setIsClosing(true); + setIsReplacing(false); + + exitTimerRef.current = window.setTimeout(() => { + setIsVisible(false); + setCurrentError(null); + setIsClosing(false); + exitTimerRef.current = null; + }, 300); + }, [clearCloseTimer, clearExitTimer]); + + useEffect(() => { + currentErrorRef.current = currentError; + }, [currentError]); useEffect(() => { // 监听自定义错误事件 @@ -23,8 +59,13 @@ export function GlobalErrorIndicator() { timestamp: Date.now(), }; + clearCloseTimer(); + clearExitTimer(); + setIsClosing(false); + setIsVisible(true); + // 如果已有错误,开始替换动画 - if (currentError) { + if (currentErrorRef.current) { setCurrentError(newError); setIsReplacing(true); @@ -36,23 +77,32 @@ export function GlobalErrorIndicator() { // 第一次显示错误 setCurrentError(newError); } - - setIsVisible(true); }; // 监听错误事件 window.addEventListener('globalError', handleError as EventListener); return () => { + clearCloseTimer(); + clearExitTimer(); window.removeEventListener('globalError', handleError as EventListener); }; - }, [currentError]); + }, [clearCloseTimer, clearExitTimer]); - const handleClose = () => { - setIsVisible(false); - setCurrentError(null); - setIsReplacing(false); - }; + useEffect(() => { + if (!currentError || isClosing) { + return; + } + + clearCloseTimer(); + closeTimerRef.current = window.setTimeout(() => { + handleClose(); + }, 5000); + + return () => { + clearCloseTimer(); + }; + }, [currentError, handleClose, isClosing, clearCloseTimer]); if (!isVisible || !currentError) { return null; @@ -63,6 +113,10 @@ export function GlobalErrorIndicator() { {/* 错误卡片 */}