use-prefetch-thread.ts4.5 KBView on GitHub import { ConversationIdState } from '@/modules/conversations/constants';
import { useQueryClient } from '@tanstack/react-query';
import { useTRPC } from '@/providers/query-provider';
import { useCallback } from 'react';
/**
* Check whether the current network connection is fast enough to justify prefetching.
* Returns true when the Network Information API is unavailable (desktop browsers)
* or when the connection is reasonably fast. Returns false on 2g / slow-2g or
* when the user has opted into data-saver mode.
*/
export function shouldPrefetch(): boolean {
const conn = (navigator as any).connection;
if (!conn) return true;
if (conn.saveData) return false;
if (conn.effectiveType === '2g' || conn.effectiveType === 'slow-2g') return false;
return true;
}
/**
* Hook for prefetching mail.get() and conversation data to improve thread loading performance.
* Uses React Query's prefetchQuery to cache data before it's needed.
*
* React Query handles deduplication and cache checking automatically, so we can
* safely call prefetch multiple times without creating redundant network requests.
*
* Common use cases:
* - Prefetch on hover over thread list items
* - Prefetch on thread selection
* - Prefetch related threads from conversation data
* - Prefetch all threads when list loads
*/
export function usePrefetchThread() {
const queryClient = useQueryClient();
const trpc = useTRPC();
/**
* Prefetch a single thread's data.
* React Query will automatically deduplicate requests and use cache if available.
* Prefetches the full thread query so it's ready when the thread is opened.
* @param threadId - The thread ID to prefetch
*/
const prefetchThread = useCallback(
(threadId: string | null | undefined) => {
if (!threadId) return;
queryClient.prefetchQuery(trpc.mail.get.queryOptions({ id: threadId }));
},
[queryClient, trpc],
);
/**
* Prefetch multiple threads in parallel.
* React Query will automatically deduplicate requests and use cache if available.
* @param threadIds - Array of thread IDs to prefetch
*/
const prefetchThreads = useCallback(
(threadIds: (string | null | undefined)[]) => {
const validIds = threadIds.filter((id): id is string => !!id);
if (validIds.length === 0) return;
// Prefetch all threads in parallel - React Query handles deduplication
// Don't pass staleTime - let each query use its own staleness criteria
validIds.forEach((threadId) => {
queryClient.prefetchQuery({
...trpc.mail.get.queryOptions({ id: threadId }),
staleTime: 3 * 60 * 1000,
});
});
},
[queryClient, trpc],
);
/**
* Check if conversationId is a special loading/failed state that requires loadConversation.
* Matches the logic in ConversationDataSync.tsx
*/
const needsLoading = (id: string | null | undefined): boolean => {
if (!id) return true; // No conversationId means we need to load
return (
id === ConversationIdState.LOADING_CONVERSATION ||
id === ConversationIdState.FAILED_CREATING_CONVERSATION
);
};
/**
* Prefetch conversation data for a thread.
* Uses the same get/load differentiation as ConversationDataSync.tsx:
* - If conversationId exists and is NOT a special state → use getConversation (faster, direct lookup)
* - If conversationId is missing or is a special state → use loadConversation (finds/creates by threadId)
* @param threadId - The thread ID
* @param conversationId - Optional conversation ID if already known
*/
const prefetchConversation = useCallback(
(threadId: string | null | undefined, conversationId?: string | null) => {
if (!threadId && !conversationId) return;
const shouldLoad = needsLoading(conversationId) && threadId;
if (!shouldLoad && conversationId) {
// Have a valid conversationId that's not a special state - use getConversation
queryClient.prefetchQuery({
...trpc.crm.getConversation.queryOptions({ id: conversationId }),
staleTime: 2 * 60 * 1000,
});
} else if (shouldLoad && threadId) {
// Need to load by threadId - use loadConversation
queryClient.prefetchQuery({
...trpc.crm.loadConversation.queryOptions({
threadId,
conversationId: conversationId || undefined,
}),
staleTime: 5 * 60 * 1000,
});
}
},
[queryClient, trpc],
);
return {
prefetchThread,
prefetchThreads,
prefetchConversation,
};
}