use-predictive-prefetch.ts1.6 KBView on GitHub import { useQueryClient } from '@tanstack/react-query';
import { useTRPC } from '@/providers/query-provider';
import { useCallback } from 'react';
/**
* Schedule a callback during browser idle time.
* Falls back to setTimeout(cb, 100) when requestIdleCallback is unavailable.
*/
function scheduleIdle(cb: () => void): void {
if (typeof requestIdleCallback !== 'undefined') {
requestIdleCallback(() => cb(), { timeout: 2000 });
} else {
setTimeout(cb, 100);
}
}
/**
* After common actions (archive, delete, send), prefetch the most likely next
* view during browser idle time so navigation feels instant.
*
* Uses requestIdleCallback to avoid blocking the main thread during action
* animations and optimistic UI updates.
*/
export function usePredictivePrefetch() {
const queryClient = useQueryClient();
const trpc = useTRPC();
const prefetchInbox = useCallback(() => {
scheduleIdle(() => {
queryClient.prefetchInfiniteQuery({
...trpc.mail.listThreads.infiniteQueryOptions(
{ q: 'label:INBOX', maxResults: 30 },
{
initialCursor: '',
getNextPageParam: (lastPage) => lastPage?.nextPageToken ?? null,
staleTime: 10_000,
},
),
pages: 1,
});
});
}, [queryClient, trpc]);
/** After archiving or deleting, user likely returns to inbox */
const afterArchiveOrDelete = useCallback(() => {
prefetchInbox();
}, [prefetchInbox]);
/** After sending an email, user likely returns to inbox */
const afterSend = useCallback(() => {
prefetchInbox();
}, [prefetchInbox]);
return { afterArchiveOrDelete, afterSend, prefetchInbox };
}