Data Hooks
The frontend uses React Query hooks to fetch and cache data from Algorand. This page documents each hook and its configuration.
usePoolState
import { usePoolState } from '@/hooks/usePoolState';
function TradeForm({ appId }: { appId: number }) {
const { data: poolState, isLoading, error } = usePoolState(appId);
if (isLoading) return <div>Loading pool...</div>;
if (error) return <div>Error: {error.message}</div>;
return <div>Reserves: {poolState.reserves}</div>;
}Configuration:
useQuery({
queryKey: ['poolState', appId],
queryFn: () => readPoolState(algodClient, appId),
staleTime: 30_000, // Data is fresh for 30s
refetchInterval: 30_000 // Poll every 30s
});useSwapQuote
import { useSwapQuote } from '@/hooks/useSwapQuote';
function QuoteDisplay({ poolState, tradeParams }) {
const { data: quote, isLoading } = useSwapQuote(
poolState,
tradeParams,
{ enabled: !!poolState } // Only fetch when poolState exists
);
return <div>Output: {quote?.amountOut}</div>;
}Configuration:
useQuery({
queryKey: ['swapQuote', poolState, tradeParams],
queryFn: () => getSwapQuote(poolState, tradeParams),
staleTime: 5_000, // Quotes expire fast
enabled: !!poolState // Don't fetch until poolState loaded
});useAllPositions
import { useAllPositions } from '@/hooks/useAllPositions';
function PortfolioView({ address, appId }: { address: string; appId: number }) {
const { data: positions } = useAllPositions(address, appId);
return (
<div>
{positions?.map((pos) => (
<PositionCard key={pos.tickId} position={pos} />
))}
</div>
);
}Configuration:
useQuery({
queryKey: ['positions', address, appId],
queryFn: () => readAllPositions(algodClient, appId, address),
staleTime: 60_000, // 1 minute
refetchInterval: 60_000
});useTokenBalances
import { useTokenBalances } from '@/hooks/useTokenBalances';
function TokenBalance({ address, asaId }) {
const { data: balance } = useTokenBalances(address, [asaId]);
return <div>Balance: {balance?.[asaId]}</div>;
}Configuration:
useQuery({
queryKey: ['tokenBalances', address, asaIds],
queryFn: () => fetchTokenBalances(algodClient, address, asaIds),
staleTime: 10_000, // 10 seconds
refetchInterval: 10_000 // Live updates
});useLivePoolMetrics
import { useLivePoolMetrics } from '@/hooks/useLivePoolMetrics';
function PoolStats({ appId }) {
const { data: metrics } = useLivePoolMetrics(appId);
return (
<div>
<div>TVL: ${metrics.tvl}</div>
<div>24h Volume: ${metrics.volume24h}</div>
</div>
);
}Configuration:
useQuery({
queryKey: ['poolMetrics', appId],
queryFn: () => fetchPoolMetrics(algodClient, appId),
staleTime: 60_000,
refetchInterval: 60_000
});usePendingTransactions
import { usePendingTransactions } from '@/hooks/usePendingTransactions';
function TxStatus({ txId }) {
const { data: status } = usePendingTransactions(txId);
return <div>Status: {status}</div>;
}Configuration:
useQuery({
queryKey: ['txStatus', txId],
queryFn: async () => {
const pending = await algodClient
.pendingTransactionInformation(txId)
.do();
if (pending['confirmed-round']) return 'confirmed';
if (pending['pool-error']) return 'failed';
return 'pending';
},
refetchInterval: 1000, // Check every second
retry: false // Don't retry on failure
});Stale Time vs Refetch Interval
| Query | Stale Time | Refetch Interval | Why |
|---|---|---|---|
| usePoolState | 30s | 30s | Pool state changes with every swap |
| useSwapQuote | 5s | - | Quotes are ephemeral, recomputed on input change |
| useAllPositions | 60s | 60s | LP positions change less frequently |
| useTokenBalances | 10s | 10s | Live balance updates for trading UX |
| usePendingTransactions | 0 | 1s | Always fresh, polling until confirmed |
Custom Query Client
// app/Providers.tsx
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: 3,
retryDelay: (attempt) => Math.min(1000 * 2 ** attempt, 30000),
networkMode: 'online', // Only fetch when online
},
},
});
export default function Providers({ children }) {
return (
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
);
}Note: All hooks are in the hooks/ directory. Import and use them in your components for consistent data fetching.