Capítulo 52 de 80

Chapter 52: QueryClient

Core Idea

QueryClient is the cache-interaction surface — beyond query/getQueryData/setQueryData covered in earlier guide chapters, it exposes bulk cache operations (invalidateQueries/refetchQueries/removeQueries/resetQueries, all sharing the QueryFilters shape) and default-option registration (setDefaultOptions/setQueryDefaults/setMutationDefaults) that apply across every query/mutation using this client.

Key Concepts

  • query(options) / infiniteQuery(options): the async fetch-and-cache primitives behind both useQuery/useInfiniteQuery and prefetching — return the resolved data (or throw), respecting cache freshness via staleTime exactly like the hook would. Don't accept the React-hook-only options (enabled, refetchInterval, refetchOnWindowFocus/Mount/Reconnect, notifyOnChangeProps, throwOnError, placeholderData), since those only make sense for a live subscription, not a one-shot fetch.
  • getQueriesData(filters) / setQueriesData(filters, updater): the bulk counterparts to getQueryData/setQueryData — operate on every query matching a QueryFilters object (prefix/exact/predicate) at once, returning/updating an array of [queryKey, data] tuples. setQueriesData never creates new cache entries, only updates existing matches.
  • setQueryData(queryKey, updater): synchronous cache write (creates the entry if it doesn't exist yet) — updater is either a raw value or a function receiving oldData. Returning undefined from an updater function (or passing undefined directly) is a no-op, useful as a "bail out of this update" signal. Updates must be immutable — never mutate oldData in place.
  • getQueryState(queryKey): reads a query's full internal state object (e.g. dataUpdatedAt, fetchStatus) — undefined if the query doesn't exist.
  • Bulk operations compared — all four accept a QueryFilters object:
    • invalidateQueries: marks matches stale, refetches only active ones by default (refetchType: 'active' | 'inactive' | 'all' | 'none' controls this) — keeps entries in cache.
    • refetchQueries: unconditionally refetches every match regardless of staleness (skips "disabled" queries and queries with staleTime: 'static' observers) — keeps entries in cache.
    • removeQueries: deletes matches from the cache outright — no refetch.
    • resetQueries: returns matches to their pre-loaded state (to initialData if set), notifying subscribers (unlike clear, which wipes subscribers too) and refetching active ones — a middle ground between invalidateQueries and a hard removeQueries+remount.
    • All four accept cancelRefetch (default true — a second overlapping call cancels and restarts the first) and (except removeQueries) throwOnError.
  • cancelQueries(filters, cancelOptions): cancels in-flight fetches matching a filter — the required first step before an optimistic setQueryData write, so a concurrent background fetch can't clobber it. Accepts the { silent, revert } cancel options.
  • isFetching(filters) / isMutating(filters): synchronous counts of in-flight queries/mutations matching a filter — useIsFetching/useIsMutating are the reactive hook equivalents.
  • Defaults registration: getDefaultOptions/setDefaultOptions (client-wide); getQueryDefaults/setQueryDefaults and getMutationDefaults/setMutationDefaults (scoped to a specific key prefix) — matching query-defaults registrations are merged, so register from most-generic key to least-generic so specific registrations correctly override generic ones.
  • getQueryCache() / getMutationCache(): access the underlying QueryCache/MutationCache instances this client is connected to — usually unnecessary, since QueryClient is the intended interaction surface.
  • clear(): wipes both caches entirely, including subscribers — more destructive than resetQueries.
  • resumePausedMutations(): resumes mutations paused by lost connectivity (networkMode: 'online''s pause behavior) — the typical call site is PersistQueryClientProvider's onSuccess, right after a persisted cache restore.

Code Examples

// Bulk update every query matching a filter, without creating new entries
queryClient.setQueriesData({ queryKey: ['todos'] }, (old) => old?.map(markDone))

// The standard optimistic-update cancel step
await queryClient.cancelQueries({ queryKey: ['todos'] })
  • What it demonstrates: a bulk cache update scoped by filter, and the cancellation step that must precede an optimistic write.

Reference Tables

MethodEffect on matchesRefetches?
invalidateQueriesMarked stale, stay in cacheActive ones (configurable)
refetchQueriesStay in cacheAll matches, unconditionally
removeQueriesDeleted from cacheNo
resetQueriesReset to initial/pre-loaded stateActive ones

Key Takeaways

  1. Reach for setQueriesData/getQueriesData (not a manual loop over getQueryData) whenever a bulk cache update needs to match a key prefix rather than one exact key.
  2. refetchQueries and invalidateQueries are not interchangeable — refetchQueries always fetches every match now; invalidateQueries only fetches active ones by default and just marks the rest stale.
  3. Register setQueryDefaults from most-generic to least-generic key — later registrations layer on top rather than short-circuiting.

Connects To

  • Filters: the QueryFilters/MutationFilters shape every bulk method here accepts.
  • QueryCache / MutationCache: the underlying storage this client wraps.
  • persistQueryClient: resumePausedMutations's typical call site.