refactor: 重构 App.js 使用 AppProviders 和 GlobalComponents

- 使用 useGlobalErrorHandler Hook 替代内联错误处理
- 使用 AppProviders 替代 6 层 Provider 嵌套
- 使用 GlobalComponents 替代分散的全局组件
- 简化 AppContent,只保留 PostHog 初始化和路由渲染

效果:
- App.js 从 165 行减少到 62 行 (-62%)
- 总计从原始 330 行减少到 62 行 (-81%)
- 代码结构清晰,职责分明

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
zdl
2025-10-30 15:03:09 +08:00
parent fffea873c4
commit 02117c6852

View File

@@ -10,81 +10,30 @@
*/ */
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import { ChakraProvider } from '@chakra-ui/react'; import { useDispatch } from 'react-redux';
// Core Components
import theme from "theme/theme.js";
// Routes // Routes
import AppRoutes from './routes'; import AppRoutes from './routes';
// Redux // Providers
import { Provider as ReduxProvider } from 'react-redux'; import AppProviders from './providers/AppProviders';
import { store } from './store';
// Contexts
import { AuthProvider } from "contexts/AuthContext";
import { AuthModalProvider } from "contexts/AuthModalContext";
import { NotificationProvider, useNotification } from "contexts/NotificationContext";
// Components // Components
import ErrorBoundary from "components/ErrorBoundary"; import GlobalComponents from './components/GlobalComponents';
import AuthModalManager from "components/Auth/AuthModalManager";
import NotificationContainer from "components/NotificationContainer";
import ConnectionStatusBar from "components/ConnectionStatusBar";
import NotificationTestTool from "components/NotificationTestTool";
import ScrollToTop from "components/ScrollToTop";
import { logger } from "utils/logger";
// PostHog Redux 集成 // Hooks
import { useDispatch } from 'react-redux'; import { useGlobalErrorHandler } from './hooks/useGlobalErrorHandler';
import { initializePostHog } from "store/slices/posthogSlice";
// Redux
import { initializePostHog } from './store/slices/posthogSlice';
// Utils
import { logger } from './utils/logger';
/** /**
* ConnectionStatusBar 包装组件 * AppContent - 应用核心内容
* 需要在 NotificationProvider 内部使用,所以单独提取 * 负责 PostHog 初始化和渲染路由
*/ */
function ConnectionStatusBarWrapper() {
const { connectionStatus, reconnectAttempt, maxReconnectAttempts, retryConnection } = useNotification();
const [isDismissed, setIsDismissed] = React.useState(false);
// 监听连接状态变化
React.useEffect(() => {
// 重连成功后,清除 dismissed 状态
if (connectionStatus === 'connected' && isDismissed) {
setIsDismissed(false);
// 从 localStorage 清除 dismissed 标记
localStorage.removeItem('connection_status_dismissed');
}
// 从 localStorage 恢复 dismissed 状态
if (connectionStatus !== 'connected' && !isDismissed) {
const dismissed = localStorage.getItem('connection_status_dismissed');
if (dismissed === 'true') {
setIsDismissed(true);
}
}
}, [connectionStatus, isDismissed]);
const handleClose = () => {
// 用户手动关闭,保存到 localStorage
setIsDismissed(true);
localStorage.setItem('connection_status_dismissed', 'true');
logger.info('App', 'Connection status bar dismissed by user');
};
return (
<ConnectionStatusBar
status={connectionStatus}
reconnectAttempt={reconnectAttempt}
maxReconnectAttempts={maxReconnectAttempts}
onRetry={retryConnection}
onClose={handleClose}
isDismissed={isDismissed}
/>
);
}
function AppContent() { function AppContent() {
const dispatch = useDispatch(); const dispatch = useDispatch();
@@ -94,73 +43,21 @@ function AppContent() {
logger.info('App', 'PostHog Redux 初始化已触发'); logger.info('App', 'PostHog Redux 初始化已触发');
}, [dispatch]); }, [dispatch]);
return ( return <AppRoutes />;
<>
{/* Socket 连接状态条 */}
<ConnectionStatusBarWrapper />
{/* 路由切换时自动滚动到顶部 */}
<ScrollToTop />
{/* 应用路由 - 从 routes/index.js 导入 */}
<AppRoutes />
</>
);
} }
/**
* App - 应用根组件
* 设置全局错误处理,提供 Provider 和全局组件
*/
export default function App() { export default function App() {
// 全局错误处理:捕获未处理的 Promise rejection // 全局错误处理
useEffect(() => { useGlobalErrorHandler();
const handleUnhandledRejection = (event) => {
logger.error('App', 'unhandledRejection', event.reason instanceof Error ? event.reason : new Error(String(event.reason)), {
promise: event.promise
});
// 阻止默认的错误处理(防止崩溃)
event.preventDefault();
};
const handleError = (event) => {
logger.error('App', 'globalError', event.error || new Error(event.message), {
filename: event.filename,
lineno: event.lineno,
colno: event.colno
});
// 阻止默认的错误处理(防止崩溃)
event.preventDefault();
};
window.addEventListener('unhandledrejection', handleUnhandledRejection);
window.addEventListener('error', handleError);
return () => {
window.removeEventListener('unhandledrejection', handleUnhandledRejection);
window.removeEventListener('error', handleError);
};
}, []);
return ( return (
<ReduxProvider store={store}> <AppProviders>
<ChakraProvider
theme={theme}
toastOptions={{
defaultOptions: {
position: 'top',
duration: 3000,
isClosable: true,
}
}}
>
<ErrorBoundary>
<NotificationProvider>
<AuthProvider>
<AppContent /> <AppContent />
<AuthModalManager /> <GlobalComponents />
<NotificationContainer /> </AppProviders>
<NotificationTestTool />
</AuthProvider>
</NotificationProvider>
</ErrorBoundary>
</ChakraProvider>
</ReduxProvider>
); );
} }