Guides
Window focus refetching
Refetch stale queries on screen when the user comes back to the tab or reconnects, with the focusRefetch() and reconnectRefetch() features, and opt queries out in meta.
When the user leaves your app and comes back, the data on screen may be out of date. Two features refetch it:
focusRefetch()refetches every read, stale query when the window regains focus.reconnectRefetch()does the same when the browser comes back online.
Neither is on by default. Add them to the client, or spread recommended(), which has both:
const const queryClient: QueryClient<{
readonly meta: Flat<Present<FocusRefetchMeta> & Present<ReconnectRefetchMeta>>;
}>
queryClient = createQueryClient<[], readonly [Feature<{
readonly meta: FocusRefetchMeta;
}>, Feature<{
readonly meta: ReconnectRefetchMeta;
}>]>(config?: QueryClientConfig & {
readonly features?: readonly [Feature<{
readonly meta: FocusRefetchMeta;
}>, Feature<{
readonly meta: ReconnectRefetchMeta;
}>] | undefined;
readonly links?: [] | undefined;
}): QueryClient<{
readonly meta: Flat<Present<FocusRefetchMeta> & Present<...>>;
}>
Create a query client. Behaviors are opt-in: pass links and features,
or spread recommended(). The client's meta type is what they declare.
createQueryClient({
features?: (readonly AnyFeature[] & readonly [Feature<{
readonly meta: FocusRefetchMeta;
}>, Feature<{
readonly meta: ReconnectRefetchMeta;
}>]) | undefined
Behaviors started while a provider has the client mounted.
features: [function focusRefetch(): Feature<{
readonly meta: FocusRefetchMeta;
}>
Refetch read, stale queries when the window regains focus, except those
with meta: { refetchOnWindowFocus: false }.
focusRefetch(), function reconnectRefetch(): Feature<{
readonly meta: ReconnectRefetchMeta;
}>
Refetch read, stale queries when the browser comes back online, except
those with meta: { refetchOnReconnect: false }.
reconnectRefetch()],
});
// or
const const withEverything: QueryClient<{
readonly meta: Flat<Present<FocusRefetchMeta> & Present<ReconnectRefetchMeta> & Present<PollingMeta> & Present<RetryMeta>>;
}>
withEverything = createQueryClient<readonly [Link<{
readonly meta: RetryMeta;
}>], readonly [Feature<{
readonly meta: FocusRefetchMeta;
}>, Feature<{
readonly meta: ReconnectRefetchMeta;
}>, Feature<{
readonly meta: PollingMeta;
}>]>(config?: QueryClientConfig & {
readonly features?: readonly [Feature<{
readonly meta: FocusRefetchMeta;
}>, Feature<{
readonly meta: ReconnectRefetchMeta;
}>, Feature<...>] | undefined;
readonly links?: readonly [...] | undefined;
}): QueryClient<...>
Create a query client. Behaviors are opt-in: pass links and features,
or spread recommended(). The client's meta type is what they declare.
createQueryClient({ ...function recommended(): RecommendedThe behaviors most apps want: retries, refetching on focus and reconnect,
and polling. Spread it into the config:
recommended() });
Only queries that a component is reading refetch, and only stale ones: data within its staleTime stays as it is. With the default staleTime of 0, that's everything on screen.
Features run while a QueryClientProvider has the client mounted, so they only ever run in the browser.
Turning it off
For every query, leave the feature out of the client:
// `recommended()` without focusRefetch() and reconnectRefetch()
const const withoutFocus: QueryClient<{
readonly meta: Flat<Present<RetryMeta> & Present<PollingMeta>>;
}>
withoutFocus = createQueryClient<readonly [Link<{
readonly meta: RetryMeta;
}>], readonly [Feature<{
readonly meta: PollingMeta;
}>]>(config?: QueryClientConfig & {
readonly features?: readonly [Feature<{
readonly meta: PollingMeta;
}>] | undefined;
readonly links?: readonly [Link<{
readonly meta: RetryMeta;
}>] | undefined;
}): QueryClient<{
readonly meta: Flat<Present<RetryMeta> & Present<PollingMeta>>;
}>
Create a query client. Behaviors are opt-in: pass links and features,
or spread recommended(). The client's meta type is what they declare.
createQueryClient({
links?: (readonly AnyLink[] & readonly [Link<{
readonly meta: RetryMeta;
}>]) | undefined
Wrap every request, outermost first.
links: [function retry(options?: RetryOptions): Link<{
readonly meta: RetryMeta;
}>
Retry failed requests. Thrown Responses (router redirects and
not-founds) and cancelled requests aren't retried,
server clients never retry, and a browser that is offline
waits until it's back online before retrying. A query sets its own
attempts with meta: { retry }.
retry()],
features?: (readonly AnyFeature[] & readonly [Feature<{
readonly meta: PollingMeta;
}>]) | undefined
Behaviors started while a provider has the client mounted.
features: [function polling(): Feature<{
readonly meta: PollingMeta;
}>
Refetch read queries every meta.refetchInterval ms.
polling()],
});
For one query, set meta: { refetchOnWindowFocus: false } or meta: { refetchOnReconnect: false } in its factory. The features declare these fields, so a factory built with a bound queryOptions gets them typed only when the root has the feature: see Query meta.
export function function settingsQuery(): QueryOptions<readonly ["account", "settings"], {
readonly theme: string;
}, {
readonly theme: string;
}, DefaultTypes>
settingsQuery() {
return queryOptions<readonly ["account", "settings"], {
readonly theme: string;
}, {
readonly theme: string;
}>(options: BaseOptions<readonly ["account", "settings"], DefaultTypes> & {
readonly queryFn: (context: QueryFunctionContext<readonly ["account", "settings"]>) => Awaitable<{
readonly theme: string;
}>;
readonly select?: ((data: {
readonly theme: string;
}) => {
readonly theme: string;
}) | undefined;
}): QueryOptions<readonly ["account", "settings"], {
readonly theme: string;
}, {
readonly theme: string;
}, DefaultTypes> (+1 overload)
Typed options for a query factory:
queryOptions({
BaseOptions<readonly ["account", "settings"], DefaultTypes>.queryKey: readonly ["account", "settings"]A plain array, usually built by a group(). Handles keep its literal type.
queryKey: account<readonly ["settings"]>(rest_0: "settings"): readonly ["account", "settings"]account("settings"),
queryFn: (context: QueryFunctionContext<readonly ["account", "settings"]>) => Awaitable<{
readonly theme: string;
}>
queryFn: () => function getSettings(): Promise<{
readonly theme: string;
}>
getSettings(),
BaseOptions<readonly ["account", "settings"], DefaultTypes>.meta?: NoInfer<Partial<Readonly<Record<string, unknown>>>> | undefinedSettings for the root's links and features, and data for targets: the
fields the root's parts declare, such as retry with the retry()
link.
meta: { refetchOnWindowFocus: booleanrefetchOnWindowFocus: false },
});
}A long staleTime is often the better fix: the data then refetches on focus only once it's actually old.
What counts as focus
focusRefetch() listens for two events:
- the document's
visibilitychangeevent, whendocument.visibilityStatebecomes"visible": switching back to the tab, restoring the window, unlocking the phone; - the window's
focusevent, while the page is visible: clicking back into the browser window from another app.
reconnectRefetch() listens for the window's online event.
To test it by hand, switch tabs and come back. See Testing for firing these events in tests.