From 48ab69befc2a8fb10d016e4217d18b14a8ce8ebd Mon Sep 17 00:00:00 2001 From: PorunC <09982.misaka@gmail.com> Date: Wed, 29 Oct 2025 20:49:22 +0800 Subject: [PATCH] Fix: Resolve React Hook violation in ComparisonChart component MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Root cause: ComparisonChart was calling useSWR hooks dynamically inside a .map() loop, which violates React's Rules of Hooks. When the traders array length changed (e.g., from 0 to 2, or during initial load), the number of hook calls would change between renders, triggering React Error #310. Previous code: ```tsx const traderHistories = traders.map((trader) => { return useSWR(`equity-history-${trader.trader_id}`, ...); // ❌ Dynamic hooks }); ``` The eslint-disable comment on line 24 was masking this critical issue. Fix: - Always call exactly 2 useSWR hooks (trader1, trader2) unconditionally - Pass null as the key when trader doesn't exist (SWR handles this gracefully) - Build traderHistories array from these fixed hooks - Ensures same number of hooks called on every render This follows React's Rules of Hooks: ✅ Only call hooks at the top level ✅ Don't call hooks inside loops, conditions, or nested functions ✅ Call hooks in the same order every render Fixes: React Error #310 (Rendered more hooks than during previous render) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- web/src/components/ComparisonChart.tsx | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/web/src/components/ComparisonChart.tsx b/web/src/components/ComparisonChart.tsx index ee94ef00..3c0b5999 100644 --- a/web/src/components/ComparisonChart.tsx +++ b/web/src/components/ComparisonChart.tsx @@ -19,14 +19,24 @@ interface ComparisonChartProps { } export function ComparisonChart({ traders }: ComparisonChartProps) { - // 获取所有trader的历史数据 - const traderHistories = traders.map((trader) => { - // eslint-disable-next-line react-hooks/rules-of-hooks - return useSWR(`equity-history-${trader.trader_id}`, () => - api.getEquityHistory(trader.trader_id), - { refreshInterval: 10000 } - ); - }); + // 获取所有trader的历史数据 - 修复: 使用固定数量的Hook调用 + // 始终调用最多2个trader的useSWR,即使实际trader数量不同 + const trader1 = traders[0]; + const trader2 = traders[1]; + + const history1 = useSWR( + trader1 ? `equity-history-${trader1.trader_id}` : null, + trader1 ? () => api.getEquityHistory(trader1.trader_id) : null, + { refreshInterval: 10000 } + ); + + const history2 = useSWR( + trader2 ? `equity-history-${trader2.trader_id}` : null, + trader2 ? () => api.getEquityHistory(trader2.trader_id) : null, + { refreshInterval: 10000 } + ); + + const traderHistories = [history1, history2].slice(0, traders.length); // 使用useMemo自动处理数据合并,直接使用data对象作为依赖 const combinedData = useMemo(() => {