修复 fallback fetch 依赖:rows.length 改为 useRef 标记,避免 terminalData 刷新时无意义 re-run
This commit is contained in:
@@ -43,7 +43,7 @@ import { scanRootClass } from "@/components/dashboard/scan-root-styles";
|
||||
import { useRelativeTime } from "@/hooks/useRelativeTime";
|
||||
import { Panel } from "@/components/dashboard/scan-terminal/Panel";
|
||||
import { TrainingDashboard } from "@/components/dashboard/scan-terminal/TrainingDashboard";
|
||||
import { LiveTemperatureThresholdChart } from "@/components/dashboard/scan-terminal/LiveTemperatureThresholdChart";
|
||||
import { LiveTemperatureThresholdChart, clearCityDetailCache } from "@/components/dashboard/scan-terminal/LiveTemperatureThresholdChart";
|
||||
import { KoyfinRowsTable } from "@/components/dashboard/scan-terminal/KoyfinRowsTable";
|
||||
import { rowName, pct, money, temp, edgeClass } from "@/components/dashboard/scan-terminal/utils";
|
||||
import { CitySelectorDropdown } from "@/components/dashboard/scan-terminal/CitySelectorDropdown";
|
||||
@@ -400,26 +400,23 @@ function PolyWeatherTerminal({
|
||||
const totalSlots = getSlotCount(gridCols, gridRows);
|
||||
|
||||
const [slots, setSlots] = useState<Array<string | null>>(() => {
|
||||
const storedCols = getStoredGridSide("polyweather_terminal_grid_cols");
|
||||
const storedRows = getStoredGridSide("polyweather_terminal_grid_rows");
|
||||
const initialSlotCount = getSlotCount(storedCols, storedRows);
|
||||
if (typeof window !== "undefined") {
|
||||
try {
|
||||
const stored = localStorage.getItem("polyweather_terminal_slots");
|
||||
if (stored) {
|
||||
const parsed = JSON.parse(stored);
|
||||
if (Array.isArray(parsed)) {
|
||||
return normalizeSlotList(parsed, initialSlotCount);
|
||||
return normalizeSlotList(parsed, MAX_TERMINAL_CHARTS);
|
||||
}
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
return Array(initialSlotCount).fill(null);
|
||||
return Array(MAX_TERMINAL_CHARTS).fill(null);
|
||||
});
|
||||
const [activeSlotIndex, setActiveSlotIndex] = useState<number>(0);
|
||||
const [maximizedSlotIndex, setMaximizedSlotIndex] = useState<number | null>(null);
|
||||
const [activeSearchSlotIndex, setActiveSearchSlotIndex] = useState<number | null>(null);
|
||||
const visibleSlots = useMemo(() => normalizeSlotList(slots, totalSlots), [slots, totalSlots]);
|
||||
const visibleSlots = useMemo(() => slots.slice(0, totalSlots), [slots, totalSlots]);
|
||||
|
||||
const handleSetGridSize = (cols: number, rows: number) => {
|
||||
const safeCols = clampGridSide(cols);
|
||||
@@ -434,13 +431,6 @@ function PolyWeatherTerminal({
|
||||
localStorage.setItem("polyweather_terminal_grid_rows", String(safeRows));
|
||||
} catch {}
|
||||
|
||||
const nextSlots = normalizeSlotList(visibleSlots, nextTotalSlots);
|
||||
|
||||
setSlots(nextSlots);
|
||||
try {
|
||||
localStorage.setItem("polyweather_terminal_slots", JSON.stringify(nextSlots));
|
||||
} catch {}
|
||||
|
||||
if (activeSlotIndex >= nextTotalSlots) {
|
||||
setActiveSlotIndex(0);
|
||||
}
|
||||
@@ -469,8 +459,8 @@ function PolyWeatherTerminal({
|
||||
}, [rows, selectedRegionKey]);
|
||||
|
||||
useEffect(() => {
|
||||
if (filteredRegionRows.length && visibleSlots.every((s) => s === null)) {
|
||||
const next = Array(totalSlots)
|
||||
if (filteredRegionRows.length && slots.every((s) => s === null)) {
|
||||
const next = Array(MAX_TERMINAL_CHARTS)
|
||||
.fill(null)
|
||||
.map((_, idx) => filteredRegionRows[idx]?.city || null);
|
||||
setSlots(next);
|
||||
@@ -478,11 +468,11 @@ function PolyWeatherTerminal({
|
||||
localStorage.setItem("polyweather_terminal_slots", JSON.stringify(next));
|
||||
} catch {}
|
||||
}
|
||||
}, [filteredRegionRows, visibleSlots, totalSlots]);
|
||||
}, [filteredRegionRows, slots]);
|
||||
|
||||
const handleSelectCityForSlot = (index: number, city: string | null) => {
|
||||
if (index < 0 || index >= totalSlots) return;
|
||||
const next = [...visibleSlots];
|
||||
if (index < 0 || index >= MAX_TERMINAL_CHARTS) return;
|
||||
const next = [...slots];
|
||||
next[index] = city;
|
||||
setSlots(next);
|
||||
try {
|
||||
@@ -860,6 +850,8 @@ function PolyWeatherTerminal({
|
||||
row={rowForSlot}
|
||||
allRows={filteredRegionRows}
|
||||
compact={true}
|
||||
isActive={isSlotActive}
|
||||
slotIndex={slotIndex}
|
||||
onSearchClick={() => setActiveSearchSlotIndex(slotIndex)}
|
||||
onMaximize={() => {
|
||||
setMaximizedSlotIndex(slotIndex);
|
||||
@@ -1025,9 +1017,24 @@ function ScanTerminalScreen() {
|
||||
timezoneOffsetSeconds: useLocalTimezoneDefault ? localTimezoneOffsetSeconds : null,
|
||||
tradingRegion: selectedRegionKey,
|
||||
});
|
||||
const handleRefresh = useCallback(() => {
|
||||
clearCityDetailCache();
|
||||
refreshScanTerminalManually();
|
||||
}, [refreshScanTerminalManually]);
|
||||
|
||||
const [cityFallbackRows, setCityFallbackRows] = useState<ScanOpportunityRow[]>([]);
|
||||
const rows = useMemo(
|
||||
() => {
|
||||
const scanRows = terminalData?.rows || [];
|
||||
return sortRowsByUserTime(scanRows.length ? scanRows : cityFallbackRows);
|
||||
},
|
||||
[cityFallbackRows, terminalData?.rows],
|
||||
);
|
||||
|
||||
const fallbackFetchedRef = useRef(false);
|
||||
useEffect(() => {
|
||||
if (!isPro || typeof fetch !== "function") return;
|
||||
if (fallbackFetchedRef.current) return;
|
||||
const controller = new AbortController();
|
||||
fetch("/api/cities", {
|
||||
cache: "no-store",
|
||||
@@ -1040,18 +1047,12 @@ function ScanTerminalScreen() {
|
||||
})
|
||||
.then((payload) => {
|
||||
if (!payload || !Array.isArray(payload.cities)) return;
|
||||
fallbackFetchedRef.current = true;
|
||||
setCityFallbackRows(cityListItemsToScanRows(payload.cities));
|
||||
})
|
||||
.catch(() => {});
|
||||
return () => controller.abort();
|
||||
}, [isPro]);
|
||||
const rows = useMemo(
|
||||
() => {
|
||||
const scanRows = terminalData?.rows || [];
|
||||
return sortRowsByUserTime(scanRows.length ? scanRows : cityFallbackRows);
|
||||
},
|
||||
[cityFallbackRows, terminalData?.rows],
|
||||
);
|
||||
const [searchQuery, setSearchQuery] = useState("");
|
||||
const searchInputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
@@ -1115,7 +1116,7 @@ function ScanTerminalScreen() {
|
||||
generatedText={generatedText || ""}
|
||||
isEn={isEn}
|
||||
locale={locale}
|
||||
onRefresh={refreshScanTerminalManually}
|
||||
onRefresh={handleRefresh}
|
||||
refreshing={scanLoading}
|
||||
rows={filteredRows}
|
||||
selectedRow={selectedRow}
|
||||
|
||||
Reference in New Issue
Block a user