53 lines
1.4 KiB
TypeScript
53 lines
1.4 KiB
TypeScript
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
import { DriftTick, fetchLatestTicks } from '../../lib/hasura';
|
|
import { useInterval } from '../../app/hooks/useInterval';
|
|
|
|
type Params = {
|
|
symbol: string;
|
|
source?: string;
|
|
limit: number;
|
|
pollMs: number;
|
|
};
|
|
|
|
type Result = {
|
|
ticks: DriftTick[];
|
|
latest: DriftTick | null;
|
|
loading: boolean;
|
|
error: string | null;
|
|
refresh: () => Promise<void>;
|
|
};
|
|
|
|
export function useTicks({ symbol, source, limit, pollMs }: Params): Result {
|
|
const [ticks, setTicks] = useState<DriftTick[]>([]);
|
|
const [loading, setLoading] = useState(false);
|
|
const [error, setError] = useState<string | null>(null);
|
|
const inFlight = useRef(false);
|
|
|
|
const fetchOnce = useCallback(async () => {
|
|
if (inFlight.current) return;
|
|
inFlight.current = true;
|
|
setLoading(true);
|
|
try {
|
|
const next = await fetchLatestTicks(symbol, limit, source?.trim() ? source : undefined);
|
|
setTicks(next);
|
|
setError(null);
|
|
} catch (e: any) {
|
|
setError(String(e?.message || e));
|
|
} finally {
|
|
setLoading(false);
|
|
inFlight.current = false;
|
|
}
|
|
}, [symbol, limit, source]);
|
|
|
|
useEffect(() => {
|
|
void fetchOnce();
|
|
}, [fetchOnce]);
|
|
|
|
useInterval(() => void fetchOnce(), pollMs);
|
|
|
|
const latest = useMemo(() => (ticks.length ? ticks[ticks.length - 1] : null), [ticks]);
|
|
|
|
return { ticks, latest, loading, error, refresh: fetchOnce };
|
|
}
|
|
|