fix: prevent scroll reset by stabilizing useEffect dependencies with refs
Run Tests / test (push) Failing after 33s
Run Tests / test (push) Failing after 33s
This commit is contained in:
+15
-6
@@ -1,4 +1,4 @@
|
|||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect, useRef, useCallback } from "react";
|
||||||
import { Link } from "react-router";
|
import { Link } from "react-router";
|
||||||
import Navbar from "../components/Navbar";
|
import Navbar from "../components/Navbar";
|
||||||
import type { TradingDecision } from "../types/agents";
|
import type { TradingDecision } from "../types/agents";
|
||||||
@@ -211,10 +211,16 @@ export default function Analyze() {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// Auto-load indicators for stocks that don't have them yet (sequential with delay to avoid rate limits)
|
// Auto-load indicators for stocks that don't have them yet (sequential with delay to avoid rate limits)
|
||||||
|
const loadingRef = useRef(false);
|
||||||
|
const stocksRef = useRef(stocks);
|
||||||
|
stocksRef.current = stocks;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const unloaded = stocks.filter((s) => !s.indicatorsLoading && s.indicators.rsi == null);
|
if (loadingRef.current) return;
|
||||||
|
const unloaded = stocksRef.current.filter((s) => !s.indicatorsLoading && s.indicators.rsi == null);
|
||||||
if (unloaded.length === 0) return;
|
if (unloaded.length === 0) return;
|
||||||
|
|
||||||
|
loadingRef.current = true;
|
||||||
let cancelled = false;
|
let cancelled = false;
|
||||||
const loadSequential = async () => {
|
const loadSequential = async () => {
|
||||||
for (const stock of unloaded) {
|
for (const stock of unloaded) {
|
||||||
@@ -227,13 +233,14 @@ export default function Analyze() {
|
|||||||
} else {
|
} else {
|
||||||
setStocks((s) => s.map((st) => st.id === stock.id ? { ...st, indicatorsLoading: false } : st));
|
setStocks((s) => s.map((st) => st.id === stock.id ? { ...st, indicatorsLoading: false } : st));
|
||||||
}
|
}
|
||||||
// 500ms delay between each stock to avoid rate limiting
|
|
||||||
await new Promise((r) => setTimeout(r, 500));
|
await new Promise((r) => setTimeout(r, 500));
|
||||||
}
|
}
|
||||||
|
loadingRef.current = false;
|
||||||
};
|
};
|
||||||
loadSequential();
|
loadSequential();
|
||||||
return () => { cancelled = true; };
|
return () => { cancelled = true; };
|
||||||
}, [stocks]);
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const interval = setInterval(() => {
|
const interval = setInterval(() => {
|
||||||
@@ -252,7 +259,8 @@ export default function Analyze() {
|
|||||||
}, 60000);
|
}, 60000);
|
||||||
|
|
||||||
return () => clearInterval(interval);
|
return () => clearInterval(interval);
|
||||||
}, [stocks]);
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, []);
|
||||||
|
|
||||||
const loadIndicators = async (ticker: string) => {
|
const loadIndicators = async (ticker: string) => {
|
||||||
try {
|
try {
|
||||||
@@ -348,7 +356,8 @@ export default function Analyze() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
updatePositions();
|
updatePositions();
|
||||||
}, [stocks.length]);
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, []);
|
||||||
|
|
||||||
const removeStock = async (id: string) => {
|
const removeStock = async (id: string) => {
|
||||||
const stock = stocks.find((s) => s.id === id);
|
const stock = stocks.find((s) => s.id === id);
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user