Domphy

Polling & Window Focus

Polling with refetchInterval

Auto-refresh data on a timer — useful for dashboards, live feeds, or anything that changes server-side:

import { QueryClient } from "@domphy/query"
import { createQuery } from "@domphy/query/domphy"

const queryClient = new QueryClient()

const stats = createQuery(queryClient, {
  queryKey: () => ["stats"],
  queryFn: fetchStats,
  refetchInterval: 5_000,   // refetch every 5 seconds
})

Polling runs in the background — the UI shows fresh data while isFetching is true.

Conditional polling

Pause polling when the data has reached a terminal state:

const queryClient = new QueryClient()

const jobStatus = createQuery(queryClient, {
  queryKey: () => ["job", jobId],
  queryFn: () => fetchJobStatus(jobId),
  refetchInterval: (query) => {
    // Stop polling when job is done or failed
    const status = query.state.data?.status
    if (status === "done" || status === "failed") return false
    return 2_000   // poll every 2 seconds while running
  },
})

refetchIntervalInBackground

By default, polling pauses when the browser tab is hidden. Enable background polling:

const queryClient = new QueryClient()

const alerts = createQuery(queryClient, {
  queryKey: () => ["alerts"],
  queryFn: fetchAlerts,
  refetchInterval: 30_000,
  refetchIntervalInBackground: true,   // keep polling even when tab is hidden
})

Window focus refetching

When the user returns to your app (tab focus, Alt+Tab), stale queries automatically refetch:

const queryClient = new QueryClient()

const data = createQuery(queryClient, {
  queryKey: () => ["dashboard"],
  queryFn: fetchDashboard,
  staleTime: 60_000,           // data is fresh for 1 minute
  refetchOnWindowFocus: true,  // refetch when window regains focus (default: true)
})

refetchOnWindowFocus triggers when:

  • User switches back to your browser tab
  • User returns from another application

Disable for data that shouldn't silently refresh:

const queryClient = new QueryClient()

const draftContent = createQuery(queryClient, {
  queryKey: () => ["draft", id],
  queryFn: () => fetchDraft(id),
  refetchOnWindowFocus: false,   // don't overwrite user edits on tab switch
})

Global config

Set defaults for all queries at the client level:

import { QueryClient } from "@domphy/query"

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 30_000,              // all queries fresh for 30s
      refetchOnWindowFocus: true,     // refetch on focus (default)
      refetchOnReconnect: true,       // refetch when network reconnects
      refetchInterval: false,         // no polling by default
      retry: 3,                       // retry 3 times on failure
      retryDelay: (attempt) => Math.min(1000 * 2 ** attempt, 30_000),
    },
  },
})

Network reconnect refetching

When the device goes offline and comes back online, stale queries automatically refetch:

const queryClient = new QueryClient()

const userProfile = createQuery(queryClient, {
  queryKey: () => ["user", userId],
  queryFn: () => fetchUser(userId),
  refetchOnReconnect: true,   // default: true
})

@domphy/query subscribes to window.addEventListener("online") — no extra setup needed.

Disabling all background refetching

For data that only refreshes on explicit user action:

const queryClient = new QueryClient()

const config = createQuery(queryClient, {
  queryKey: () => ["config"],
  queryFn: fetchConfig,
  staleTime: Infinity,            // never goes stale
  refetchOnWindowFocus: false,    // no focus refetch
  refetchOnReconnect: false,      // no reconnect refetch
  refetchInterval: false,         // no polling
})

// Refresh only on explicit button click
const RefreshButton = {
  button: "Refresh config",
  onClick: () => config.refetch(),
}

refetch() on demand

Trigger a refetch manually without invalidating the cache:

const queryClient = new QueryClient()

const feed = createQuery(queryClient, {
  queryKey: () => ["feed"],
  queryFn: fetchFeed,
})

const RefreshFeed = {
  button: "↻ Refresh",
  onClick: () => feed.refetch(),
  disabled: (l) => feed.isFetching(l),
}

Detecting staleness

Check if the current data is stale (older than staleTime):

const query = client.getQueryState(["stats"])
const isStale = query?.isStale ?? true   // true if data is older than staleTime

// Or reactively:
const isStale = (l) => {
  const state = client.getQueryState(["stats"])
  return state ? Date.now() - (state.dataUpdatedAt ?? 0) > 30_000 : true
}

Online status indicator

Show the user when the app is offline:

import { onlineManager } from "@domphy/query"
import { toState } from "@domphy/core"

const isOnline = toState(onlineManager.isOnline())

onlineManager.subscribe((online) => isOnline.set(online))

const OfflineBanner = {
  div: "You're offline — data may be outdated",
  hidden: (l) => isOnline.get(l),
  style: {
    background: "var(--warning-3)",
    color: "var(--warning-11)",
    padding: "8px 16px",
    textAlign: "center",
  },
}