From afdbacaabd75407965c4ad3321c7ab5ee9be07c4 Mon Sep 17 00:00:00 2001 From: 21in7 Date: Sat, 7 Mar 2026 14:31:28 +0900 Subject: [PATCH] fix(dashboard): prevent infinite API polling loop useCallback dependency on `symbols` state caused fetchAll to recreate on every call (since it sets symbols), triggering useEffect to restart the interval immediately. Use symbolsRef to break the cycle. Co-Authored-By: Claude Opus 4.6 --- dashboard/ui/src/App.jsx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/dashboard/ui/src/App.jsx b/dashboard/ui/src/App.jsx index a863d18..0e61f86 100644 --- a/dashboard/ui/src/App.jsx +++ b/dashboard/ui/src/App.jsx @@ -267,6 +267,7 @@ export default function App() { const [lastUpdate, setLastUpdate] = useState(null); const [symbols, setSymbols] = useState([]); + const symbolsRef = useRef([]); const [selectedSymbol, setSelectedSymbol] = useState(null); // null = ALL const [stats, setStats] = useState({ @@ -283,7 +284,7 @@ export default function App() { /* ── 데이터 폴링 ─────────────────────────────────────────── */ const fetchAll = useCallback(async () => { const sym = selectedSymbol ? `?symbol=${selectedSymbol}` : ""; - const symRequired = selectedSymbol || symbols[0] || "XRPUSDT"; + const symRequired = selectedSymbol || symbolsRef.current[0] || "XRPUSDT"; const [symRes, sRes, pRes, tRes, dRes, cRes] = await Promise.all([ api("/symbols"), @@ -294,7 +295,10 @@ export default function App() { api(`/candles?symbol=${symRequired}&limit=96`), ]); - if (symRes?.symbols) setSymbols(symRes.symbols); + if (symRes?.symbols) { + symbolsRef.current = symRes.symbols; + setSymbols(symRes.symbols); + } if (sRes && sRes.total_trades !== undefined) { setStats(sRes); setIsLive(true); @@ -307,7 +311,7 @@ export default function App() { if (tRes?.trades) setTrades(tRes.trades); if (dRes?.daily) setDaily(dRes.daily); if (cRes?.candles) setCandles(cRes.candles); - }, [selectedSymbol, symbols]); + }, [selectedSymbol]); useEffect(() => { fetchAll();