intermediate
TanStack Query
Use query keys, stale time, cache time, mutations, invalidation, retries, and optimistic updates deliberately.
TanStack Query (React Query) caches async state by query keys. `useQuery` fetches and tracks status; `useMutation` writes with optional optimistic updates and invalidation.
const { data, isLoading, error } = useQuery({
queryKey: ['todos', filter],
queryFn: () => fetchTodos(filter),
staleTime: 60_000,
});
const mutation = useMutation({
mutationFn: addTodo,
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),
});
| Option | Role | |--------|------| | queryKey | Cache identity — include all variables | | staleTime | How long data feels fresh without refetch | | gcTime | How long unused cache survives | | enabled | Skip fetch until condition true |
Prefetch on hover, parallel queries with `useQueries`, and shared `QueryClient` for SSR dehydration.
The trade-off is powerful cache orchestration versus key design discipline and stale UI if defaults are ignored.
On interviews: key design, stale vs garbage collection, mutation + invalidation flow.
Common pitfalls: unstable query keys (inline objects), global staleTime zero causing refetch storms, and mutations without optimistic rollback plan.
Checklist:
- Stable hierarchical query keys.
- Tune staleTime per data type.
- invalidateQueries or setQueryData after writes.
- Dehydrate/hydrate for SSR carefully.