use-prefetch-folder-threads.ts2.2 KBView on GitHub import { useCallback, useRef } from 'react';
import { useQueryClient } from '@tanstack/react-query';
import { useTRPC } from '@/providers/query-provider';
import { getSystemFolderSplit } from '@/modules/threads/lib/system-folder-splits';
/**
* Prefetches thread list data for a folder on hover, so navigating
* to that folder feels instant. Uses a 100ms debounce to avoid
* firing on casual mouse-overs.
*
* The query key and input shape intentionally match the pattern in
* `useThreads` so the prefetched data is reused by the real query.
*/
export function usePrefetchFolderThreads() {
const queryClient = useQueryClient();
const trpc = useTRPC();
const timerRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);
const prefetch = useCallback(
(folderPath: string) => {
if (timerRef.current) clearTimeout(timerRef.current);
timerRef.current = setTimeout(() => {
// Extract folder name from path like "/mail/inbox" -> "inbox"
const folder = folderPath.split('/').pop() || 'inbox';
const systemSplit = getSystemFolderSplit(folder);
const usesSplitPath = folder === 'inbox' || !!systemSplit;
queryClient.prefetchInfiniteQuery({
...trpc.mail.listThreads.infiniteQueryOptions(
{
q: usesSplitPath ? undefined : `label:${folder}`,
inboxName: folder === 'inbox' ? 'Inbox' : systemSplit?.inboxName,
compiledQuery:
folder === 'inbox' ? 'label:INBOX' : systemSplit?.compiledQuery,
queryHash:
folder === 'inbox'
? 'system-folder:inbox:label:INBOX'
: systemSplit?.queryHash,
maxResults: 30,
},
{
initialCursor: '',
getNextPageParam: (lastPage) => lastPage?.nextPageToken ?? null,
staleTime: 30_000,
},
),
// `pages` belongs to prefetchInfiniteQuery, not to the query options.
pages: 1,
});
}, 100);
},
[queryClient, trpc],
);
const cancel = useCallback(() => {
if (timerRef.current) clearTimeout(timerRef.current);
}, []);
return { prefetch, cancel };
}