From f50bda7c884d7eb2221cbcadf9c3522b92ce2940 Mon Sep 17 00:00:00 2001 From: 0age <37939117+0age@users.noreply.github.com> Date: Thu, 5 Dec 2024 20:55:32 -0800 Subject: [PATCH] fix rerendering balances --- frontend/src/components/BalanceDisplay.tsx | 57 ++------------- frontend/src/hooks/useBalances.ts | 80 ++++++++++++++++++++++ 2 files changed, 84 insertions(+), 53 deletions(-) create mode 100644 frontend/src/hooks/useBalances.ts diff --git a/frontend/src/components/BalanceDisplay.tsx b/frontend/src/components/BalanceDisplay.tsx index 7ceb01a..4e07e59 100644 --- a/frontend/src/components/BalanceDisplay.tsx +++ b/frontend/src/components/BalanceDisplay.tsx @@ -1,62 +1,13 @@ import { useAccount } from 'wagmi'; -import { useState, useEffect } from 'react'; - -interface Balance { - chainId: string; - lockId: string; - allocatableBalance: string; - allocatedBalance: string; - balanceAvailableToAllocate: string; - withdrawalStatus: number; -} +import { useBalances } from '../hooks/useBalances'; export function BalanceDisplay() { - const { address, isConnected } = useAccount(); - const [balances, setBalances] = useState([]); - const [loading, setLoading] = useState(false); - const [error, setError] = useState(null); - - useEffect(() => { - async function fetchBalances() { - if (!isConnected || !address) return; - - setLoading(true); - setError(null); - - try { - const sessionId = localStorage.getItem(`session-${address}`); - if (!sessionId) { - throw new Error('No session ID found'); - } - - const response = await fetch('/balances', { - headers: { - 'x-session-id': sessionId - } - }); - if (!response.ok) throw new Error('Failed to fetch balances.'); - - const data = await response.json(); - setBalances(data.balances); - } catch (err) { - setError(err instanceof Error ? err.message : 'Failed to fetch balances'); - } finally { - setLoading(false); - } - } - - fetchBalances(); - - // Set up polling interval - const intervalId = setInterval(fetchBalances, 5000); - - // Cleanup on unmount or address change - return () => clearInterval(intervalId); - }, [isConnected, address]); + const { isConnected } = useAccount(); + const { balances, error, isLoading } = useBalances(); if (!isConnected) return null; - if (loading) { + if (isLoading) { return (
diff --git a/frontend/src/hooks/useBalances.ts b/frontend/src/hooks/useBalances.ts new file mode 100644 index 0000000..73d8a2a --- /dev/null +++ b/frontend/src/hooks/useBalances.ts @@ -0,0 +1,80 @@ +import { useState, useEffect, useRef, useCallback } from 'react'; +import { useAccount } from 'wagmi'; + +interface Balance { + chainId: string; + lockId: string; + allocatableBalance: string; + allocatedBalance: string; + balanceAvailableToAllocate: string; + withdrawalStatus: number; +} + +interface UseBalancesResult { + balances: Balance[]; + error: string | null; + isLoading: boolean; +} + +export function useBalances(): UseBalancesResult { + const { address, isConnected } = useAccount(); + const [balances, setBalances] = useState([]); + const [error, setError] = useState(null); + const [isLoading, setIsLoading] = useState(false); + const isFetchingRef = useRef(false); + + const fetchBalances = useCallback(async () => { + if (!isConnected || !address || isFetchingRef.current) return; + + isFetchingRef.current = true; + + try { + const sessionId = localStorage.getItem(`session-${address}`); + if (!sessionId) { + throw new Error('No session ID found'); + } + + const response = await fetch('/balances', { + headers: { + 'x-session-id': sessionId + } + }); + + if (!response.ok) throw new Error('Failed to fetch balances.'); + + const data = await response.json(); + + // Only update state if data has actually changed + setBalances(prevBalances => { + const newBalances = data.balances; + const hasChanged = JSON.stringify(prevBalances) !== JSON.stringify(newBalances); + return hasChanged ? newBalances : prevBalances; + }); + + setError(null); + } catch (err) { + setError(err instanceof Error ? err.message : 'Failed to fetch balances'); + } finally { + isFetchingRef.current = false; + } + }, [isConnected, address]); + + useEffect(() => { + // Initial load should show loading state + if (isConnected && address) { + setIsLoading(true); + fetchBalances().finally(() => setIsLoading(false)); + } + + // Set up polling interval + const intervalId = setInterval(fetchBalances, 5000); + + // Cleanup on unmount or address change + return () => { + clearInterval(intervalId); + isFetchingRef.current = false; + }; + }, [fetchBalances, isConnected, address]); + + return { balances, error, isLoading }; +}