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:
151
src/App.js
151
src/App.js
@@ -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>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user