초기로딩 부하문제 수정
This commit is contained in:
+61
-18
@@ -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>
|
||||
)}
|
||||
|
||||
{/* ── 실시간 차트 화면 ────────────────────────────────────────────── */}
|
||||
|
||||
Reference in New Issue
Block a user