全局错误框自动消失
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useEffect, useState } from 'react';
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
|
|
||||||
interface ErrorInfo {
|
interface ErrorInfo {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -12,6 +12,42 @@ export function GlobalErrorIndicator() {
|
|||||||
const [currentError, setCurrentError] = useState<ErrorInfo | null>(null);
|
const [currentError, setCurrentError] = useState<ErrorInfo | null>(null);
|
||||||
const [isVisible, setIsVisible] = useState(false);
|
const [isVisible, setIsVisible] = useState(false);
|
||||||
const [isReplacing, setIsReplacing] = useState(false);
|
const [isReplacing, setIsReplacing] = useState(false);
|
||||||
|
const [isClosing, setIsClosing] = useState(false);
|
||||||
|
const currentErrorRef = useRef<ErrorInfo | null>(null);
|
||||||
|
const closeTimerRef = useRef<number | null>(null);
|
||||||
|
const exitTimerRef = useRef<number | null>(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(() => {
|
useEffect(() => {
|
||||||
// 监听自定义错误事件
|
// 监听自定义错误事件
|
||||||
@@ -23,8 +59,13 @@ export function GlobalErrorIndicator() {
|
|||||||
timestamp: Date.now(),
|
timestamp: Date.now(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
clearCloseTimer();
|
||||||
|
clearExitTimer();
|
||||||
|
setIsClosing(false);
|
||||||
|
setIsVisible(true);
|
||||||
|
|
||||||
// 如果已有错误,开始替换动画
|
// 如果已有错误,开始替换动画
|
||||||
if (currentError) {
|
if (currentErrorRef.current) {
|
||||||
setCurrentError(newError);
|
setCurrentError(newError);
|
||||||
setIsReplacing(true);
|
setIsReplacing(true);
|
||||||
|
|
||||||
@@ -36,23 +77,32 @@ export function GlobalErrorIndicator() {
|
|||||||
// 第一次显示错误
|
// 第一次显示错误
|
||||||
setCurrentError(newError);
|
setCurrentError(newError);
|
||||||
}
|
}
|
||||||
|
|
||||||
setIsVisible(true);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 监听错误事件
|
// 监听错误事件
|
||||||
window.addEventListener('globalError', handleError as EventListener);
|
window.addEventListener('globalError', handleError as EventListener);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
|
clearCloseTimer();
|
||||||
|
clearExitTimer();
|
||||||
window.removeEventListener('globalError', handleError as EventListener);
|
window.removeEventListener('globalError', handleError as EventListener);
|
||||||
};
|
};
|
||||||
}, [currentError]);
|
}, [clearCloseTimer, clearExitTimer]);
|
||||||
|
|
||||||
const handleClose = () => {
|
useEffect(() => {
|
||||||
setIsVisible(false);
|
if (!currentError || isClosing) {
|
||||||
setCurrentError(null);
|
return;
|
||||||
setIsReplacing(false);
|
}
|
||||||
};
|
|
||||||
|
clearCloseTimer();
|
||||||
|
closeTimerRef.current = window.setTimeout(() => {
|
||||||
|
handleClose();
|
||||||
|
}, 5000);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
clearCloseTimer();
|
||||||
|
};
|
||||||
|
}, [currentError, handleClose, isClosing, clearCloseTimer]);
|
||||||
|
|
||||||
if (!isVisible || !currentError) {
|
if (!isVisible || !currentError) {
|
||||||
return null;
|
return null;
|
||||||
@@ -63,6 +113,10 @@ export function GlobalErrorIndicator() {
|
|||||||
{/* 错误卡片 */}
|
{/* 错误卡片 */}
|
||||||
<div
|
<div
|
||||||
className={`bg-red-500 text-white px-4 py-3 rounded-lg shadow-lg flex items-center justify-between min-w-[300px] max-w-[400px] transition-all duration-300 ${
|
className={`bg-red-500 text-white px-4 py-3 rounded-lg shadow-lg flex items-center justify-between min-w-[300px] max-w-[400px] transition-all duration-300 ${
|
||||||
|
isClosing
|
||||||
|
? '-translate-y-4 opacity-0'
|
||||||
|
: 'translate-y-0 opacity-100'
|
||||||
|
} ${
|
||||||
isReplacing ? 'scale-105 bg-red-400' : 'scale-100 bg-red-500'
|
isReplacing ? 'scale-105 bg-red-400' : 'scale-100 bg-red-500'
|
||||||
} animate-fade-in`}
|
} animate-fade-in`}
|
||||||
>
|
>
|
||||||
|
|||||||
Reference in New Issue
Block a user