TanStack Query 接入 · TanStack Query Setup

SkillDev tools

Initialize or refactor a frontend project to use TanStack Query as the unified server-state layer. Use when the user asks to install TanStack Query, initialize query infrastructure, migrate ad hoc fetch/invoke/useEffect request state, standardize query keys, or make app network requests share one cache model. Also trigger when the user mentions "初始化 TanStack Query", "重构网络请求", "统一请求缓存", "install-tanstack-query", "TanStack Query refactor", or "useInvokeQuery".

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the TanStack Query 接入 · TanStack Query Setup skill

What this skill tells your AI

The instructions your AI receives, as published by lovstudio/skills in skills/install-tanstack-query/SKILL.md and read by ahel’s review.

Use this skill to add TanStack Query to a project or refactor existing request state into a shared query/mutation layer.

When to Use

  • The user asks to install or initialize TanStack Query / React Query.
  • The project has repeated useEffect + useState + fetch/invoke request code.
  • The user wants all network-backed reads to share cache, refetch, invalidation, and loading/error behavior.
  • A Tauri app uses many invoke() reads that should be treated as server state.
  • The user mentions RTK Query but the project already uses, or prefers, TanStack Query.

Workflow

Step 1: Read Local Rules First

Before changing files, inspect local instructions and project shape:

pwd
find .. -name AGENTS.md -print
rg -n "@tanstack/react-query|react-query|@reduxjs/toolkit|createApi|useQuery|useMutation|fetch\\(|invoke\\(" package.json src app pages components 2>/dev/null

Honor project-specific constraints. If local instructions say not to run build, do not run it. Prefer rg and inspect existing patterns before adding new abstractions.

Step 2: Classify Request Code

Separate code into three buckets:

BucketExamplesTanStack Query?
Server state readslist/get/search/version/status/catalog/settings loaded from network or Tauri backendYes, useQuery
Server state writessave/delete/toggle/install request, followed by cache changesYes, useMutation
Imperative side effectsterminal I/O, file open, clipboard, app relaunch, installer progress events, streaming channelsUsually no

Do not force command-style effects into Query just to make the code look uniform. The goal is unified server state, not hiding every side effect.

Step 3: Install Only If Needed

Check package.json first. If TanStack Query is absent, detect package manager from lockfiles and install:

pnpm add @tanstack/react-query
npm install @tanstack/react-query
yarn add @tanstack/react-query
bun add @tanstack/react-query

Only add persistence or devtools when the project already uses them or the user explicitly asks:

pnpm add @tanstack/react-query-persist-client @tanstack/query-sync-storage-persister
pnpm add -D @tanstack/react-query-devtools

Step 4: Add Provider

Add one top-level QueryClientProvider near the app root. Keep it consistent with the existing architecture.

Recommended defaults:

import { QueryClient, QueryClientProvider } from "@tanstack/react-query";

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: Infinity,
      refetchOnWindowFocus: false,
      retry: false,
    },
  },
});

root.render(
  <QueryClientProvider client={queryClient}>
    <App />
  </QueryClientProvider>,
);

Adjust defaults for product needs. Data that changes frequently should use a shorter staleTime, polling, streaming, or explicit invalidation.

Step 5: Create Shared Query Infrastructure

Prefer small local wrappers over scattering raw useQuery calls everywhere.

For Tauri apps:

import { invoke } from "@tauri-apps/api/core";
import {
  useMutation,
  useQuery,
  useQueryClient,
  type QueryKey,
  type UseQueryOptions,
  type UseMutationOptions,
} from "@tanstack/react-query";

type InvokeQueryOptions<TQueryFnData, TData> = Omit<
  UseQueryOptions<TQueryFnData, Error, TData, QueryKey>,
  "queryKey" | "queryFn"
>;

export function useInvokeQuery<TQueryFnData, TData = TQueryFnData>(
  queryKey: QueryKey,
  command: string,
  args?: Record<string, unknown>,
  options?: InvokeQueryOptions<TQueryFnData, TData>,
) {
  return useQuery<TQueryFnData, Error, TData, QueryKey>({
    queryKey,
    queryFn: () => invoke<TQueryFnData>(command, args),
    staleTime: Infinity,
    refetchOnMount: false,
    refetchOnWindowFocus: false,
    ...options,
  });
}

type InvokeMutationOptions<T, V> = Omit<UseMutationOptions<T, Error, V>, "mutationFn">;

export function useInvokeMutation<T, V = void>(
  command: string,
  invalidateKeys?: QueryKey[],
  options?: InvokeMutationOptions<T, V>,
) {
  const queryClient = useQueryClient();
  return useMutation<T, Error, V>({
    mutationFn: (variables) => invoke<T>(command, variables as Record<string, unknown>),
    ...options,
    onSuccess: (data, variables, context, mutation) => {
      options?.onSuccess?.(data, variables, context, mutation);
      invalidateKeys?.forEach((key) => {
        queryClient.invalidateQueries({ queryKey: key });
      });
    },
  });
}

Add stable query keys:

export const queryKeys = {
  projects: ["projects"] as const,
  settings: ["settings"] as const,
};

For REST apps, use the same structure but wrap the project's API client instead of Tauri invoke().

Step 6: Refactor Incrementally

Start with duplicated and user-visible requests:

  1. Replace manual read state:
const { data = [], isLoading, error, refetch } = useInvokeQuery<Item[]>(
  queryKeys.items,
  "list_items",
);
  1. Replace write requests:
const saveItem = useInvokeMutation<Item, { item: Item }>(
  "save_item",
  [queryKeys.items],
);
  1. Use queryClient.setQueryData() for optimistic toggles when the UX needs instant feedback.

  2. Keep local UI state local. Dialog open state, form drafts, selected tabs, and filters usually do not belong in TanStack Query.

  3. Do not break existing streaming subscriptions. If a stream already pushes data into queryClient.setQueryData(), keep that pattern.

Step 7: Verification

Run the lightest reliable checks allowed by the repo:

pnpm exec tsc --noEmit --pretty false
npm run typecheck
yarn typecheck
bun run typecheck

Do not run heavy builds or dev server commands if local instructions forbid them. For UI-heavy changes, suggest browser verification or screenshots after type checks pass.

Final Response Checklist

Report:

  • What query provider/wrappers/keys were added or reused.
  • Which request flows moved to TanStack Query.
  • Which imperative flows intentionally stayed command-driven.
  • Which checks were run and whether any warnings remain.

Runtime context (shared)

运行前读取本 Skill 包的 skill.yaml,由宿主提供 skill-runtime/v1 上下文。字段解析顺序为:当前请求、项目上下文、个人 Preferences、品牌 Profile、通用默认值。

  • 只使用 Manifest 声明的字段;Profile 保存公开品牌事实,Preferences 保存个人工作偏好。
  • required: true 字段缺失时,按 Manifest 的问题配置向用户提出一个聚焦问题;用户明确同意后再保存回答。
  • 报错提供可复制的 context_id、字段路径与来源,诊断内容避开秘密、完整私人路径和原始配置。

通用反馈闭环

用户在 Skill 驱动任务中提出修改意见时,继续当前产物前必须执行:

  1. 先判断意见是 task-specific(仅本次)还是 reusable(可跨任务复用)。
  2. task-specific 只修改当前任务,不改 Skill。
  3. reusable 先确定作用域:领域规则先更新对应 canonical Skill;适用于所有 Skill 的规则先更新共享规范。
  4. 完成规则更新、版本、lint 与分发核验后,再把修改应用到当前任务。
  5. reusable 修改会使此前的“确认”“继续”“发吧”失效;完成当前产物修改和回读后必须停下,等待用户下一步指示,不自动进入发布、提交或其他外部写入。

Signals

GitHub stars
66
Forks
17
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
lov-install-tanstack-query
Source
github.com/lovstudio/skills