Skip to content

Commit aa36baf

Browse files
committed
fix: 优化应用状态流转和添加背景组件错误处理
- 修复首次访问状态流转逻辑(intro -> splash -> ready) - 添加 isInitialized 状态防止渲染时序问题 - 为 Background3D 和 ParticleBackground 添加 ErrorFallback 包装 - 确保背景组件错误时使用纯色降级显示 - 移除未使用的 skipToIntro 回调函数 问题修复: - 修复首次访问后不显示引导页直接进入的问题 - 修复背景组件错误导致白屏问题 - 确保所有状态转换都有正确的 loading 状态
1 parent def8e5e commit aa36baf

3 files changed

Lines changed: 63 additions & 12 deletions

File tree

src/App.tsx

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,18 @@ function App() {
1616
const location = useLocation()
1717
const [appState, setAppState] = useState<'intro' | 'splash' | 'ready'>('intro')
1818
const [isFirstVisit, setIsFirstVisit] = useState<boolean | null>(null)
19+
const [isInitialized, setIsInitialized] = useState(false)
1920

2021
useEffect(() => {
2122
const hasVisited = localStorage.getItem('human-os-visited')
2223
if (hasVisited) {
2324
setIsFirstVisit(false)
24-
setAppState('ready')
25+
setAppState('splash')
2526
} else {
2627
setIsFirstVisit(true)
28+
setAppState('intro')
2729
}
30+
setIsInitialized(true)
2831
}, [])
2932

3033
useEffect(() => {
@@ -37,20 +40,15 @@ function App() {
3740

3841
const handleIntroComplete = useCallback(() => {
3942
localStorage.setItem('human-os-visited', 'true')
43+
setIsFirstVisit(false)
4044
setAppState('splash')
4145
}, [])
4246

4347
const handleSplashComplete = useCallback(() => {
4448
setAppState('ready')
4549
}, [])
4650

47-
const skipToIntro = useCallback(() => {
48-
if (isFirstVisit === false) {
49-
setAppState('ready')
50-
}
51-
}, [isFirstVisit])
52-
53-
if (isFirstVisit === null) {
51+
if (!isInitialized || isFirstVisit === null) {
5452
return (
5553
<div className="fixed inset-0 bg-slate-950 flex items-center justify-center">
5654
<motion.div
@@ -72,7 +70,7 @@ function App() {
7270
return (
7371
<>
7472
<AnimatePresence mode="wait">
75-
{appState === 'intro' && isFirstVisit && (
73+
{appState === 'intro' && (
7674
<motion.div
7775
key="intro"
7876
initial={{ opacity: 1 }}

src/components/ErrorFallback.tsx

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { useState, useEffect, ReactNode } from 'react'
2+
import { motion } from 'framer-motion'
3+
4+
interface FallbackProps {
5+
children: ReactNode
6+
fallback: ReactNode
7+
onError?: () => void
8+
}
9+
10+
export default function ErrorFallback({ children, fallback, onError }: FallbackProps) {
11+
const [hasError, setHasError] = useState(false)
12+
13+
useEffect(() => {
14+
const handleError = (event: ErrorEvent) => {
15+
console.error('Component Error:', event.error)
16+
setHasError(true)
17+
onError?.()
18+
}
19+
20+
const handleRejection = (event: PromiseRejectionEvent) => {
21+
console.error('Unhandled Promise Rejection:', event.reason)
22+
setHasError(true)
23+
onError?.()
24+
}
25+
26+
window.addEventListener('error', handleError)
27+
window.addEventListener('unhandledrejection', handleRejection)
28+
29+
return () => {
30+
window.removeEventListener('error', handleError)
31+
window.removeEventListener('unhandledrejection', handleRejection)
32+
}
33+
}, [onError])
34+
35+
if (hasError) {
36+
return <>{fallback}</>
37+
}
38+
39+
return <>{children}</>
40+
}

src/components/Layout.tsx

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,31 @@
1-
import { ReactNode } from 'react'
1+
import { ReactNode, ComponentType } from 'react'
22
import Navbar from './Navbar'
33
import Footer from './Footer'
44
import Background3D from './Background3D'
55
import ParticleBackground from './ParticleBackground'
6+
import ErrorFallback from './ErrorFallback'
67

78
interface LayoutProps {
89
children: ReactNode
910
}
1011

12+
function Background3DWrapper() {
13+
return <Background3D />
14+
}
15+
16+
function ParticleBackgroundWrapper() {
17+
return <ParticleBackground />
18+
}
19+
1120
export default function Layout({ children }: LayoutProps) {
1221
return (
1322
<div className="relative min-h-screen bg-gradient-mesh overflow-hidden">
14-
<Background3D />
15-
<ParticleBackground />
23+
<ErrorFallback fallback={<div className="fixed inset-0 bg-slate-950" />}>
24+
<Background3DWrapper />
25+
</ErrorFallback>
26+
<ErrorFallback fallback={<div className="fixed inset-0 bg-slate-950/50" />}>
27+
<ParticleBackgroundWrapper />
28+
</ErrorFallback>
1629
<div className="relative z-10">
1730
<Navbar />
1831
<main className="min-h-[calc(100vh-64px-80px)]">

0 commit comments

Comments
 (0)