@cardql/react
Version:
CardQL SDK for React web applications with hooks and context providers
113 lines (97 loc) • 2.52 kB
text/typescript
import { useState, useEffect, useCallback, useRef } from "react";
import { useCardQLClient } from "../context";
export interface UseQueryOptions {
enabled?: boolean;
refetchOnMount?: boolean;
refetchInterval?: number;
onSuccess?: (data: any) => void;
onError?: (error: any) => void;
}
export interface UseQueryResult<T> {
data: T | undefined;
loading: boolean;
error: any;
refetch: () => Promise<void>;
refresh: () => Promise<void>;
}
/**
* Hook for executing GraphQL queries with CardQL
*/
export function useQuery<T = any>(
query: string,
variables?: any,
options: UseQueryOptions = {}
): UseQueryResult<T> {
const cardql = useCardQLClient();
const [data, setData] = useState<T | undefined>(undefined);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<any>(null);
const {
enabled = true,
refetchOnMount = true,
refetchInterval,
onSuccess,
onError,
} = options;
const intervalRef = useRef<number>();
const mountedRef = useRef(true);
const fetchData = useCallback(async () => {
if (!enabled) return;
setLoading(true);
setError(null);
try {
const result = await cardql.client.requestWithRetry<T>(query, variables);
if (mountedRef.current) {
setData(result);
setLoading(false);
onSuccess?.(result);
}
} catch (err) {
if (mountedRef.current) {
setError(err);
setLoading(false);
onError?.(err);
}
}
}, [cardql, query, variables, enabled, onSuccess, onError]);
const refetch = useCallback(async () => {
await fetchData();
}, [fetchData]);
const refresh = useCallback(async () => {
setData(undefined);
await fetchData();
}, [fetchData]);
// Initial fetch
useEffect(() => {
if (enabled && refetchOnMount) {
fetchData();
}
}, [enabled, refetchOnMount, fetchData]);
// Set up refetch interval
useEffect(() => {
if (refetchInterval && enabled) {
intervalRef.current = setInterval(fetchData, refetchInterval);
return () => {
if (intervalRef.current) {
clearInterval(intervalRef.current);
}
};
}
}, [refetchInterval, enabled, fetchData]);
// Cleanup on unmount
useEffect(() => {
return () => {
mountedRef.current = false;
if (intervalRef.current) {
clearInterval(intervalRef.current);
}
};
}, []);
return {
data,
loading,
error,
refetch,
refresh,
};
}