Capítulo 46 de 80
@tanstack/eslint-plugin-query catches the mistakes this skill's guides repeatedly warn about — missing key dependencies, unstable QueryClient instances, rest-destructuring that defeats tracked properties — as lint errors instead of runtime bugs; install it via flat/recommended (or flat/recommended-strict for more opinionated rules) and it enforces most of these patterns automatically.
npm i -D @tanstack/eslint-plugin-query); flat config spreads pluginQuery.configs['flat/recommended'] (or 'flat/recommended-strict') into the config array, or you can cherry-pick individual rules under the @tanstack/query plugin namespace. Legacy .eslintrc uses "extends": ["plugin:@tanstack/query/recommended"] the same way.exhaustive-deps (recommended, fixable): enforces that every value a queryFn closes over is present in queryKey — the automated version of the Query Keys chapter's dependency rule. Function call targets (fetchTodoById itself) aren't dependencies; values referenced inside nested callbacks still are. Configurable allowlist.variables/allowlist.types to exempt stable values (e.g. an injected API client) from the check.stable-query-client (recommended, fixable): flags constructing new QueryClient() inline in a component body (a new client every render) — require it in useState(() => new QueryClient()), module scope, or (the one exception) an async Server Component, which only runs once server-side.no-rest-destructuring (recommended, not fixable): flags const { data, ...rest } = useQuery(...) because rest destructuring subscribes to every field, silently defeating tracked-properties re-render skipping (Chapter 39). Also flags rest destructuring on custom hooks that themselves return a query result, under typed linting. Safe to disable if notifyOnChangeProps is already being set manually.no-unstable-deps (recommended, not fixable): flags passing a whole query/mutation hook's return object directly into another hook's dependency array (useEffect/useMemo/useCallback) — that object isn't referentially stable across renders. Destructure the specific value(s) needed (e.g. mutate from useMutation) and depend on those instead.infinite-query-property-order (recommended, fixable): for useInfiniteQuery/useSuspenseInfiniteQuery/infiniteQueryOptions, TypeScript's inference is order-sensitive — queryFn, then getPreviousPageParam, then getNextPageParam must appear in that relative order for correct type inference; other properties are order-insensitive.no-void-query-fn (recommended, not fixable): flags a queryFn that never returns a value (e.g. await api.todos.fetch() with no return) — this silently produces undefined, an illegal successful cache value.mutation-property-order (recommended, fixable): same order-sensitivity issue as infinite queries, but for useMutation() — onMutate, then onError, then onSettled must appear in that relative order.prefer-query-options (recommended in the strict config only, not fixable): flags a bare { queryKey, queryFn } object passed straight to useQuery instead of wrapped in queryOptions() — and separately flags re-typing a queryKey array literal in queryClient calls (getQueryData(['todo', id])) instead of reusing optionsFn(id).queryKey from the shared queryOptions() definition, which risks the literal drifting out of sync with the real key.| Rule | Recommended | Auto-fixable | Enforces |
|---|---|---|---|
exhaustive-deps | Yes | Yes | Every queryFn dependency is in queryKey |
stable-query-client | Yes | Yes | QueryClient isn't recreated every render |
no-rest-destructuring | Yes | No | No rest-destructuring of query results |
no-unstable-deps | Yes | No | Query hook results aren't passed whole into dep arrays |
infinite-query-property-order | Yes | Yes | queryFn → getPreviousPageParam → getNextPageParam order |
no-void-query-fn | Yes | No | queryFn always returns a value |
mutation-property-order | Yes | Yes | onMutate → onError → onSettled order |
prefer-query-options | Strict only | No | queryOptions() used instead of raw key/fn pairs, key reused not re-typed |
flat/recommended on any new project — it's the automated enforcement of nearly every "gotcha" covered across the Guides chapters, and half the rules auto-fix.allowlist option on exhaustive-deps for genuinely stable injected values (API clients, config objects) rather than disabling the rule wholesale.flat/recommended-strict (which adds prefer-query-options) once a codebase has more than a couple of shared query keys — it prevents key literals from silently drifting apart across call sites.exhaustive-deps automates.no-rest-destructuring.queryOptions(), enforced by prefer-query-options.