TanStack Query + TanStack DB: Predictable Data and Local Editing
The biggest issues I see in data-heavy React apps are consistency issues: unstable keys, ad-hoc invalidation, and unclear ownership of state.
These are the patterns I use to keep it boring and predictable.
1) TanStack Query: treat query keys like an API
If caching feels like magic, your keys are probably unstable. Fix it with a key factory.
type Filters = { q?: string; status?: "active" | "archived" }
export const userKeys = {
all: ["users"] as const,
list: (filters: Filters) => [...userKeys.all, "list", filters] as const,
detail: (id: string) => [...userKeys.all, "detail", id] as const,
}
Usage
useQuery({
queryKey: userKeys.detail(id),
queryFn: () => api.users.get(id),
staleTime: 30_000,
})
Invalidation
await updateUser.mutateAsync(input)
queryClient.invalidateQueries({ queryKey: userKeys.all })
Rule: invalidate by “area”, not by guessing exact keys.
2) TanStack DB: local-first state without the chaos
TanStack DB works best when you treat it like a local model that can sync — not like “yet another global store”.
The pattern is simple:
3) Dirty tracking is not optional
If you edit locally, you need a real definition of “changed”. Make it explicit and test it.
import isEqual from "lodash.isequal"
const isDirty = !isEqual(remoteValue, localDraft)