# network-mode: Configure Network Mode for Offline Support ## Priority: LOW ## Explanation TanStack Query's `networkMode` controls how queries and mutations behave when there's no network connection. Configure it based on your app's offline requirements: always fetch, pause when offline, or work entirely offline. ## Bad Example ```tsx // Not considering offline behavior const { data } = useQuery({ queryKey: ['todos'], queryFn: fetchTodos, // Default networkMode: 'online' // Query pauses with no feedback when offline }) // User goes offline, sees stale data with no indication // Mutations silently queue with no UI feedback ``` ## Good Example: Default Online Mode with Offline UI ```tsx // Show clear offline state to users function TodoList() { const { data, fetchStatus, status } = useQuery({ queryKey: ['todos'], queryFn: fetchTodos, networkMode: 'online', // Default - pauses when offline }) // fetchStatus: 'fetching' | 'paused' | 'idle' // 'paused' means waiting for network return (
{fetchStatus === 'paused' && ( You're offline. Showing cached data. )}
) } ``` ## Good Example: Always Mode for Offline-First ```tsx // App works offline with local data const { data, error } = useQuery({ queryKey: ['todos'], queryFn: async () => { // Try network first try { const todos = await fetchTodosFromServer() await saveToLocalDB(todos) // Sync to local return todos } catch (e) { // Fall back to local data return getFromLocalDB() } }, networkMode: 'always', // Always runs queryFn, even offline }) // Or set globally const queryClient = new QueryClient({ defaultOptions: { queries: { networkMode: 'always', }, mutations: { networkMode: 'always', }, }, }) ``` ## Good Example: Offline-First Mode ```tsx // Only fetch when online, but don't fail when offline const { data } = useQuery({ queryKey: ['user-preferences'], queryFn: fetchPreferences, networkMode: 'offlineFirst', // Runs queryFn once, then waits for network if it fails // Good for: data that's useful to attempt offline }) ``` ## Good Example: Mutation Offline Queue ```tsx function TodoApp() { const queryClient = useQueryClient() const addTodo = useMutation({ mutationFn: createTodo, networkMode: 'online', // Pauses when offline onMutate: async (newTodo) => { // Optimistic update works offline await queryClient.cancelQueries({ queryKey: ['todos'] }) const previous = queryClient.getQueryData(['todos']) queryClient.setQueryData(['todos'], (old: Todo[]) => [...old, newTodo]) return { previous } }, onError: (err, newTodo, context) => { queryClient.setQueryData(['todos'], context?.previous) }, onSettled: () => { queryClient.invalidateQueries({ queryKey: ['todos'] }) }, }) // Track paused mutations const pendingMutations = useMutationState({ filters: { status: 'pending' }, }) const pausedMutations = pendingMutations.filter( m => m.state.isPaused ) return (
{pausedMutations.length > 0 && ( {pausedMutations.length} changes waiting to sync )}
) } ``` ## Network Mode Comparison | Mode | Behavior | Use Case | |------|----------|----------| | `'online'` (default) | Pauses when offline, resumes when online | Most apps, show offline state | | `'always'` | Always runs queryFn regardless of network | Offline-first apps, local-only data | | `'offlineFirst'` | Tries once, then waits for network if fails | Best-effort offline | ## Good Example: Online Status Detection ```tsx import { onlineManager } from '@tanstack/react-query' // React to online/offline changes function NetworkStatus() { const isOnline = useSyncExternalStore( onlineManager.subscribe, () => onlineManager.isOnline(), ) return (
{isOnline ? 'Connected' : 'Offline'}
) } // Manually override online detection (for testing) onlineManager.setOnline(false) ``` ## Context - Default `'online'` mode is best for most apps - `fetchStatus: 'paused'` indicates waiting for network - Mutations queue automatically and retry when back online - Use `onlineManager` to detect and control online state - Combine with optimistic updates for seamless offline UX - Consider service workers for true offline support