Back to Ragflow

network-mode: Configure Network Mode for Offline Support

web/.agents/skills/tanstack-query-best-practices/rules/network-mode.md

0.25.14.5 KB
Original Source

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 (
    <div>
      {fetchStatus === 'paused' && (
        <Banner>You're offline. Showing cached data.</Banner>
      )}
      <TodoItems todos={data} />
    </div>
  )
}

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 (
    <div>
      {pausedMutations.length > 0 && (
        <Banner>
          {pausedMutations.length} changes waiting to sync
        </Banner>
      )}
      <TodoList />
    </div>
  )
}

Network Mode Comparison

ModeBehaviorUse Case
'online' (default)Pauses when offline, resumes when onlineMost apps, show offline state
'always'Always runs queryFn regardless of networkOffline-first apps, local-only data
'offlineFirst'Tries once, then waits for network if failsBest-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 (
    <div className={isOnline ? 'online' : 'offline'}>
      {isOnline ? 'Connected' : 'Offline'}
    </div>
  )
}

// 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