Creating a separate hook for every endpoint quickly becomes noisy, especially when the response shape varies. By defining a single generic useApi hook you let TypeScript infer the payload type from the function you pass in, while React Query still handles caching, retries, and background refetching. This pattern keeps your component code clean and guarantees that you only ever access fields that exist on the response.
import { useQuery, UseQueryOptions } from '@tanstack/react-query';
import { fetch } from 'expo-network';
// Generic hook
function useApi<T>(
key: string[],
url: string,
options?: UseQueryOptions<T>
) {
return useQuery<T>(key, async () => {
const res = await fetch(url);
return (await res.json()) as T;
}, options);
}
// Usage in a component
type User = { id: string; name: string; email: string };
const { data, isLoading } = useApi<User>(['user', id], `/api/users/${id}`);Wrap your fetch logic in a single generic hook and let TypeScript do the heavy lifting. You’ll get autocomplete for response fields, fewer duplicate hooks, and a consistent caching strategy across your app.