Functions.jsx 컴포넌트 분할: 1,583→460줄 (3훅+8컴포넌트+유틸)
- lottoUtils.jsx: 공통 유틸·상수 추출 (Ball, NumberRow, 통계 헬퍼 등) - hooks/useLottoData.js: 핵심 데이터 로드 (최신회차, 통계, 시뮬레이션, 리포트) - hooks/usePurchases.js: 구매 기록 CRUD - hooks/useManualRecommend.js: 수동 추천 + 히스토리 - components/: MetricBlock, FrequencyChart, PerformanceBanner, ConfidenceRing, CombinedRecommendPanel, ReportPanel, PersonalAnalysisPanel, PurchasePanel 분리 - getReport import 누락 버그 수정 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
162
src/pages/lotto/hooks/useLottoData.js
Normal file
162
src/pages/lotto/hooks/useLottoData.js
Normal file
@@ -0,0 +1,162 @@
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import {
|
||||
getLatest, getStats, getBestPicks, getAnalysis,
|
||||
getPerformanceStats, getLatestReport, getReportHistory, getReport,
|
||||
getPersonalAnalysis, getCombinedRecommend, getCombinedHistory,
|
||||
} from '../../../api';
|
||||
import { readStatsCache, writeStatsCache } from '../lottoUtils';
|
||||
|
||||
export default function useLottoData() {
|
||||
const [latest, setLatest] = useState(null);
|
||||
const [stats, setStats] = useState(() => readStatsCache());
|
||||
const [statsLoading, setStatsLoading] = useState(false);
|
||||
const [statsError, setStatsError] = useState('');
|
||||
const [loading, setLoading] = useState({
|
||||
latest: false, bestPicks: false, analysis: false,
|
||||
});
|
||||
const [error, setError] = useState('');
|
||||
const [bestPicks, setBestPicks] = useState([]);
|
||||
const [bestPicksExpanded, setBestPicksExpanded] = useState(false);
|
||||
const [analysis, setAnalysis] = useState(null);
|
||||
const [simulating, setSimulating] = useState(false);
|
||||
const [simResult, setSimResult] = useState(null);
|
||||
|
||||
// 종합 추론
|
||||
const [combined, setCombined] = useState(null);
|
||||
const [combinedLoading, setCombinedLoading] = useState(false);
|
||||
const [combinedHistory, setCombinedHistory] = useState([]);
|
||||
const [combinedHistLoading, setCombinedHistLoading] = useState(false);
|
||||
|
||||
// 신뢰도·리포트·개인분석
|
||||
const [perfStats, setPerfStats] = useState(null);
|
||||
const [report, setReport] = useState(null);
|
||||
const [reportHistory, setReportHistory] = useState([]);
|
||||
const [reportLoading, setReportLoading] = useState(false);
|
||||
const [personalAnalysis, setPersonalAnalysis] = useState(null);
|
||||
const [personalLoading, setPersonalLoading] = useState(false);
|
||||
|
||||
const refreshLatest = useCallback(async () => {
|
||||
setLoading((s) => ({ ...s, latest: true }));
|
||||
setError('');
|
||||
try { setLatest(await getLatest()); }
|
||||
catch (e) { setError(e?.message ?? String(e)); }
|
||||
finally { setLoading((s) => ({ ...s, latest: false })); }
|
||||
}, []);
|
||||
|
||||
const refreshStats = useCallback(async () => {
|
||||
setStatsLoading(true); setStatsError('');
|
||||
try {
|
||||
const cached = readStatsCache();
|
||||
if (cached && !stats) setStats(cached);
|
||||
const data = await getStats();
|
||||
if (!cached || cached.total_draws !== data?.total_draws) {
|
||||
setStats(data); writeStatsCache(data);
|
||||
}
|
||||
} catch (e) { setStatsError(e?.message ?? String(e)); }
|
||||
finally { setStatsLoading(false); }
|
||||
}, [stats]);
|
||||
|
||||
const refreshBestPicks = useCallback(async () => {
|
||||
setLoading((s) => ({ ...s, bestPicks: true }));
|
||||
try { setBestPicks((await getBestPicks(20)).items ?? []); }
|
||||
catch {}
|
||||
finally { setLoading((s) => ({ ...s, bestPicks: false })); }
|
||||
}, []);
|
||||
|
||||
const refreshAnalysis = useCallback(async () => {
|
||||
setLoading((s) => ({ ...s, analysis: true }));
|
||||
try { setAnalysis(await getAnalysis()); }
|
||||
catch {}
|
||||
finally { setLoading((s) => ({ ...s, analysis: false })); }
|
||||
}, []);
|
||||
|
||||
const refreshPerfStats = useCallback(async () => {
|
||||
try { setPerfStats(await getPerformanceStats()); } catch {}
|
||||
}, []);
|
||||
|
||||
const refreshReport = useCallback(async () => {
|
||||
setReportLoading(true);
|
||||
try {
|
||||
const [rep, hist] = await Promise.all([
|
||||
getLatestReport(),
|
||||
getReportHistory(10),
|
||||
]);
|
||||
setReport(rep);
|
||||
setReportHistory(hist?.reports ?? []);
|
||||
} catch {}
|
||||
finally { setReportLoading(false); }
|
||||
}, []);
|
||||
|
||||
const loadSpecificReport = useCallback(async (drwNo) => {
|
||||
setReportLoading(true);
|
||||
try { setReport(await getReport(drwNo)); }
|
||||
catch {}
|
||||
finally { setReportLoading(false); }
|
||||
}, []);
|
||||
|
||||
const runCombinedRecommend = useCallback(async () => {
|
||||
setCombinedLoading(true);
|
||||
try {
|
||||
const data = await getCombinedRecommend();
|
||||
setCombined(data);
|
||||
const hist = await getCombinedHistory(30);
|
||||
setCombinedHistory(hist?.items ?? []);
|
||||
} catch (e) { setError(e?.message ?? String(e)); }
|
||||
finally { setCombinedLoading(false); }
|
||||
}, []);
|
||||
|
||||
const loadCombinedHistory = useCallback(async () => {
|
||||
setCombinedHistLoading(true);
|
||||
try {
|
||||
const hist = await getCombinedHistory(30);
|
||||
setCombinedHistory(hist?.items ?? []);
|
||||
} catch {}
|
||||
finally { setCombinedHistLoading(false); }
|
||||
}, []);
|
||||
|
||||
const refreshPersonalAnalysis = useCallback(async () => {
|
||||
setPersonalLoading(true);
|
||||
try { setPersonalAnalysis(await getPersonalAnalysis()); }
|
||||
catch {}
|
||||
finally { setPersonalLoading(false); }
|
||||
}, []);
|
||||
|
||||
const onSimulate = useCallback(async () => {
|
||||
const ok = confirm('시뮬레이션을 즉시 실행할까요?\n20,000개 후보를 분석합니다. (약 1~3분 소요)');
|
||||
if (!ok) return;
|
||||
setSimulating(true); setSimResult(null); setError('');
|
||||
try {
|
||||
const { triggerSimulate } = await import('../../../api');
|
||||
const data = await triggerSimulate();
|
||||
setSimResult(data);
|
||||
await refreshBestPicks();
|
||||
} catch (e) { setError(e?.message ?? String(e)); }
|
||||
finally { setSimulating(false); }
|
||||
}, [refreshBestPicks]);
|
||||
|
||||
// 초기 로드
|
||||
useEffect(() => {
|
||||
refreshLatest();
|
||||
refreshStats();
|
||||
refreshBestPicks();
|
||||
refreshAnalysis();
|
||||
refreshPerfStats();
|
||||
refreshReport();
|
||||
refreshPersonalAnalysis();
|
||||
loadCombinedHistory();
|
||||
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
return {
|
||||
latest, loading, error, setError,
|
||||
stats, statsLoading, statsError, refreshStats,
|
||||
refreshLatest,
|
||||
bestPicks, bestPicksExpanded, setBestPicksExpanded, refreshBestPicks,
|
||||
analysis, refreshAnalysis,
|
||||
simulating, simResult, onSimulate,
|
||||
combined, combinedLoading, combinedHistory, combinedHistLoading,
|
||||
runCombinedRecommend,
|
||||
perfStats,
|
||||
report, reportHistory, reportLoading, refreshReport, loadSpecificReport,
|
||||
personalAnalysis, personalLoading,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user