초기로딩 부하문제 수정

This commit is contained in:
Macbook
2026-05-31 22:26:54 +09:00
parent 4f2d98d4ba
commit 32d735c172
8 changed files with 554 additions and 387 deletions
+61 -18
View File
@@ -1,4 +1,4 @@
import React, { useState, useEffect, useLayoutEffect, useCallback, useRef, useMemo } from 'react';
import React, { useState, useEffect, useLayoutEffect, useCallback, useRef, useMemo, lazy, Suspense } from 'react';
import DrawingToolbar from './components/DrawingToolbar';
import BottomBar from './components/BottomBar';
import TradingChart from './components/TradingChart';
@@ -78,8 +78,6 @@ import { clampVirtualTargetMax } from './utils/virtualTargetLimits';
import { resolveTrendSearchAppSettings } from './utils/trendSearchAppSettings';
import MarketPanel from './components/MarketPanel';
import TopMenuBar, { type MenuPage } from './components/TopMenuBar';
import StrategyPage from './components/StrategyPage';
import StrategyEditorPage from './components/StrategyEditorPage';
import BacktestPanel from './components/BacktestPanel';
import { useBacktest } from './hooks/useBacktest';
import LiveStrategyPanel from './components/LiveStrategyPanel';
@@ -95,16 +93,23 @@ import {
} from './utils/tradingAccess';
import { NotifyTopMenuBar, ChartToolbarNotify } from './components/NotifyUiBindings';
import { AppNotificationLayer } from './components/AppNotificationLayer';
import TradeNotificationListPage from './components/TradeNotificationListPage';
import BacktestSettingsModal from './components/BacktestSettingsModal';
import { BacktestResultModal } from './components/BacktestResultModal';
import { BacktestHistoryPage } from './components/BacktestHistoryPage';
import SettingsPage from './components/SettingsPage';
import PaperTradingPage from './components/PaperTradingPage';
import VirtualTradingPage from './components/VirtualTradingPage';
import TrendSearchPage from './components/TrendSearchPage';
import VerificationBoardPage from './components/VerificationBoardPage';
import DashboardPage from './components/DashboardPage';
const DashboardPage = lazy(() => import('./components/DashboardPage'));
const StrategyPage = lazy(() => import('./components/StrategyPage'));
const StrategyEditorPage = lazy(() => import('./components/StrategyEditorPage'));
const TradeNotificationListPage = lazy(() => import('./components/TradeNotificationListPage'));
const BacktestHistoryPage = lazy(() => import('./components/BacktestHistoryPage').then(m => ({ default: m.BacktestHistoryPage })));
const SettingsPage = lazy(() => import('./components/SettingsPage'));
const PaperTradingPage = lazy(() => import('./components/PaperTradingPage'));
const VirtualTradingPage = lazy(() => import('./components/VirtualTradingPage'));
const TrendSearchPage = lazy(() => import('./components/TrendSearchPage'));
const VerificationBoardPage = lazy(() => import('./components/VerificationBoardPage'));
function PageLoadFallback() {
return <div className="page-load-fallback" role="status"> </div>;
}
import { loadPaperSummary, resetPaperAccount, loadActiveLiveStrategySettings, expandLiveStrategySubscriptions } from './utils/backendApi';
import ChartLegendBar from './components/ChartLegendBar';
import { resolveChartLiveQuote } from './utils/chartLiveQuote';
@@ -236,8 +241,14 @@ function App() {
const chartVisible = menuPage === 'chart';
const isMobile = useIsMobile();
// ── 마켓 패널 시세 데이터 ─────────────────────────────────────────────
const { tickers: marketTickers, loading: marketLoading, usdRate } = useMarketTicker();
const priorityMarketsRef = useRef<string[]>([symbol]);
const getPriorityMarkets = useCallback(() => priorityMarketsRef.current, []);
const marketTickerOpts = useMemo(() => ({
lite: isMobile && !showMarketPanel,
loadFull: !isMobile || showMarketPanel,
getPriorityMarkets,
}), [isMobile, showMarketPanel, getPriorityMarkets]);
const { tickers: marketTickers, loading: marketLoading, usdRate } = useMarketTicker(marketTickerOpts);
// ── 레이아웃 상태 ─────────────────────────────────────────────────────
const [layoutDef, setLayoutDef] = useState<LayoutDef>(() => LAYOUTS[0]);
@@ -297,7 +308,9 @@ function App() {
}, [saveAppDef]);
const chartSymbol = layoutDef.count > 1 ? activeSlotSymbol : symbol;
const { orderbook, wsStatus: obWsStatus, spread } = useUpbitOrderbook(chartSymbol);
const chartScreenActive = menuPage === 'chart';
const orderbookEnabled = chartScreenActive && isUpbitMarket(chartSymbol);
const { orderbook, wsStatus: obWsStatus, spread } = useUpbitOrderbook(chartSymbol, orderbookEnabled);
const chartTicker = marketTickers.get(chartSymbol);
const orderbookPrevClose = chartTicker
? (chartTicker.tradePrice ?? 0) - (chartTicker.changePrice ?? 0)
@@ -548,6 +561,10 @@ function App() {
: [...UPBIT_MARKETS.slice(0, 5), ...SYMBOLS.slice(0, 4)];
return [...new Set([...base, ...getFavorites()])];
});
priorityMarketsRef.current = useMemo(
() => [symbol, ...watchlist],
[symbol, watchlist],
);
/** 좌측 패널 관심종목(gc_favorites) — 종목 검색 드롭다운 별표·실시간 전략과 동기화 */
const [favoritesList, setFavoritesList] = useState<string[]>(getFavorites);
// DB 로드 완료 여부 (false → DB 로드 전, localStorage 기반 동작)
@@ -1751,30 +1768,45 @@ function App() {
{/* ── 투자전략 화면 ──────────────────────────────────────────────── */}
{menuPage === 'dashboard' && (
<DashboardPage theme={theme} onGoChart={m => { goToMarketChart(m); setMenuPage('chart'); }} />
<Suspense fallback={<PageLoadFallback />}>
<DashboardPage theme={theme} onGoChart={m => { goToMarketChart(m); setMenuPage('chart'); }} />
</Suspense>
)}
{menuPage === 'strategy' && (
formalLogin
? <StrategyPage theme={theme} activeIndicators={indicators} />
? (
<Suspense fallback={<PageLoadFallback />}>
<StrategyPage theme={theme} activeIndicators={indicators} />
</Suspense>
)
: <FormalLoginGate onLogin={requireFormalLogin} />
)}
{menuPage === 'strategy-editor' && (
formalLogin
? <StrategyEditorPage theme={theme} />
? (
<Suspense fallback={<PageLoadFallback />}>
<StrategyEditorPage theme={theme} />
</Suspense>
)
: <FormalLoginGate onLogin={requireFormalLogin} />
)}
{/* ── 백테스팅 이력 화면 ─────────────────────────────────────────── */}
{menuPage === 'backtest' && (
formalLogin
? <BacktestHistoryPage theme={theme} />
? (
<Suspense fallback={<PageLoadFallback />}>
<BacktestHistoryPage theme={theme} />
</Suspense>
)
: <FormalLoginGate onLogin={requireFormalLogin} />
)}
{menuPage === 'paper' && (
formalLogin ? (
<Suspense fallback={<PageLoadFallback />}>
<PaperTradingPage
theme={theme}
tickers={marketTickers}
@@ -1793,6 +1825,7 @@ function App() {
setMenuPage('chart');
}}
/>
</Suspense>
) : (
<FormalLoginGate onLogin={requireFormalLogin} title="투자관리" />
)
@@ -1800,6 +1833,7 @@ function App() {
{menuPage === 'virtual' && (
formalLogin ? (
<Suspense fallback={<PageLoadFallback />}>
<VirtualTradingPage
theme={theme}
tickers={marketTickers}
@@ -1810,12 +1844,14 @@ function App() {
onPaperAutoTradeEnabled={v => saveAppDef({ paperAutoTradeEnabled: v })}
onPaperOrderFilled={handlePaperOrderFilled}
/>
</Suspense>
) : (
<FormalLoginGate onLogin={requireFormalLogin} title="가상매매" />
)
)}
{menuPage === 'trend-search' && (
<Suspense fallback={<PageLoadFallback />}>
<TrendSearchPage
theme={theme}
chartRealtimeSource={(appDefaults.chartRealtimeSource ?? 'BACKEND_STOMP') as ChartRealtimeSource}
@@ -1823,19 +1859,23 @@ function App() {
chartSeriesPriceLabels={appDefaults.chartSeriesPriceLabels}
tickers={marketTickers}
/>
</Suspense>
)}
{menuPage === 'verification-board' && (
<Suspense fallback={<PageLoadFallback />}>
<VerificationBoardPage
theme={theme}
focusIssueId={verificationFocusIssueId}
onFocusIssueConsumed={() => setVerificationFocusIssueId(null)}
/>
</Suspense>
)}
{/* ── 설정 화면 ──────────────────────────────────────────────────── */}
{menuPage === 'notifications' && canMenu('notifications') && (
formalLogin ? (
<Suspense fallback={<PageLoadFallback />}>
<TradeNotificationListPage
theme={theme}
tickers={marketTickers}
@@ -1848,12 +1888,14 @@ function App() {
setMenuPage('chart');
}}
/>
</Suspense>
) : (
<FormalLoginGate onLogin={requireFormalLogin} title="알림목록" />
)
)}
{menuPage === 'settings' && canMenu('settings') && (
<Suspense fallback={<PageLoadFallback />}>
<SettingsPage
isFormalLogin={formalLogin}
onRequireFormalLogin={requireFormalLogin}
@@ -1990,6 +2032,7 @@ function App() {
}}
initialCategory={settingsInitialCategory}
/>
</Suspense>
)}
{/* ── 실시간 차트 화면 ────────────────────────────────────────────── */}