Agent SkillsTangleML/tangle-ui › tanstack-query

tanstack-query

GitHub

提供 TanStack Query v5 的服务端状态管理最佳实践,涵盖查询定义、缓存键规范、Suspense 及突变模式,指导开发者高效处理数据获取与缓存。

.claude/skills/tanstack-query/SKILL.md TangleML/tangle-ui

Trigger Scenarios

编写数据获取逻辑 配置服务端状态缓存 实现数据突变操作

Install

npx skills add TangleML/tangle-ui --skill tanstack-query -g -y
More Options

Non-standard path

npx skills add https://github.com/TangleML/tangle-ui/tree/master/.claude/skills/tanstack-query -g -y

Use without installing

npx skills use TangleML/tangle-ui@tanstack-query

指定 Agent (Claude Code)

npx skills add TangleML/tangle-ui --skill tanstack-query -a claude-code -g -y

安装 repo 全部 skill

npx skills add TangleML/tangle-ui --all -g -y

预览 repo 内 skill

npx skills add TangleML/tangle-ui --list

SKILL.md

Frontmatter
{
    "name": "tanstack-query",
    "description": "TanStack Query v5 patterns for data fetching, mutations, and cache management. Use when writing queries, mutations, or working with server state."
}

TanStack Query Patterns

This project uses TanStack Query v5 for all server state management.

Prefer useQuery hooks over Context providers for server state. When you need data from the server, first consider whether a custom useQuery hook solves the problem. Only reach for a Context provider when you need to share non-query app-wide state (theme, feature flags, backend config). Wrapping query results in Context bypasses TanStack Query's built-in caching and causes unnecessary re-renders.

Query Key Conventions

Use hierarchical array-based keys. For domains with multiple related queries, use a query key factory:

export const SecretsQueryKeys = {
  All: () => ["secrets"] as const,
  Id: (id: string) => ["secrets", id] as const,
} as const;

Standalone queries just use a simple key:

queryKey: ["pipeline-run", rootExecutionId];
queryKey: ["execution-details", rootExecutionId];
queryKey: ["component", "hydrate", componentQueryKey];

Query Definition

Define queries inline in custom hooks — this project does not use the queryOptions helper:

export function usePipelineRuns(pipelineName?: string) {
  return useSuspenseQuery({
    queryKey: ["pipelineRuns", pipelineName],
    queryFn: async () => {
      if (!pipelineName) return [];
      const res = await fetchPipelineRuns(pipelineName);
      if (!res) return [];
      return res.runs;
    },
    staleTime: 5 * MINUTES,
    refetchOnWindowFocus: false,
    refetchOnMount: false,
  });
}

Suspense Queries

Use useSuspenseQuery for components wrapped in <SuspenseWrapper> or error boundaries:

export function useHydrateComponentReference(component: ComponentReference) {
  const { data } = useSuspenseQuery({
    queryKey: ["component", "hydrate", getComponentQueryKey(component)],
    staleTime: 1000 * 60 * 60,
    queryFn: () => hydrateComponentReference(component),
  });
  return data;
}

Dependent Queries

Chain queries using the enabled option:

const { data: rootExecutionId } = useQuery({
  queryKey: ["pipeline-run-execution-id", id],
  queryFn: () =>
    fetchPipelineRun(id, backendUrl).then((res) => res.root_execution_id),
  enabled: !!id && id.length > 0,
});

const { data: executionData } = useQuery({
  enabled: !!rootExecutionId && !!executionDetails,
  queryKey: ["pipeline-run", rootExecutionId],
  queryFn: () => fetchData(rootExecutionId),
});

Mutation Pattern

All mutations follow this structure — invalidate cache on success, toast on error:

const { mutate, isPending } = useMutation({
  mutationFn: () => addSecret(secret),
  onSuccess: () => {
    void queryClient.invalidateQueries({ queryKey: SecretsQueryKeys.All() });
    onSuccess();
  },
  onError: () => {
    notify("Failed to add secret", "error");
  },
});

Multiple invalidations in a single mutation are fine:

onSuccess: () => {
  queryClient.invalidateQueries({ queryKey: ["has-component", digest] });
  queryClient.invalidateQueries({ queryKey: ["componentLibrary", "publishedComponents"] });
},

Cache Invalidation Strategy

This project uses post-mutation invalidation, not optimistic updates. Do not use setQueryData in mutations — invalidate and let the query refetch.

QueryClient methods used:

  • queryClient.invalidateQueries() — primary invalidation
  • queryClient.fetchQuery() — direct fetch in non-hook contexts (e.g., class-based libraries)
  • queryClient.getQueryData() — cache reading without triggering refetch
  • queryClient.ensureQueryData() — fetch-if-not-cached for recursive/dependent data

Stale Time Guidelines

Match stale time to data volatility:

Data Type Stale Time Example
Immutable/rare changes 24 hours Pipeline run metadata, component digests
User profile data 30 minutes User details
Semi-stable data 1 hour Execution details, component hydration
Active lists 5 minutes Pipeline runs, published components, outdated checks
Live/polling data 5 seconds Logs
Always fresh 0 User components

Use time constants from src/utils/constants.ts: ONE_MINUTE_IN_MS, MINUTES, HOURS, TWENTY_FOUR_HOURS_IN_MS.

Polling with Dynamic Intervals

Use refetchInterval with a function for conditional polling:

refetchInterval: (data) => {
  if (data instanceof Query) {
    const { state } = data.state.data || {};
    if (!state) return false;
    return isExecutionComplete(stats) ? false : 5000;
  }
  return false;
},

Error Handling

  • Use .catch(() => undefined) for controlled fallbacks in queryFn
  • Use onError with toast notifications in mutations
  • Create custom error classes for domain-specific errors (e.g., ComponentHydrationError)

File Organization

  • Service functions (API calls): src/services/
  • Query hooks: src/hooks/ or co-located in component directories
  • Query key factories: co-located with the feature (e.g., types.ts in the feature folder)
  • Providers using queries: src/providers/

Version History

  • d7768e8 Current 2026-09-02 20:59

Same Skill Collection

.claude/skills/accessibility/SKILL.md
.claude/skills/address-pr-comments/SKILL.md
.claude/skills/analytics-tracking/SKILL.md
.claude/skills/audit-tickets/SKILL.md
.claude/skills/docs-update/SKILL.md
.claude/skills/e2e-testing/SKILL.md
.claude/skills/list-skills/SKILL.md
.claude/skills/open-source/SKILL.md
.claude/skills/project-conventions/SKILL.md
.claude/skills/react-patterns/SKILL.md
.claude/skills/review/SKILL.md
.claude/skills/tangle-domain/SKILL.md
.claude/skills/tanstack-router/SKILL.md
.claude/skills/typescript-standards/SKILL.md
.claude/skills/ui-primitives/SKILL.md
.claude/skills/validate/SKILL.md
.claude/skills/vitest-testing/SKILL.md
.cursor/skills/playwright-testing/SKILL.md
public/agent-skills/componentYamlFormat/SKILL.md
public/agent-skills/tangleBestPractices/SKILL.md
.claude/skills/gardening/SKILL.md

Metadata

Files
0
Version
d7768e8
Hash
7f1da53e
Indexed
2026-09-02 20:59

inicio - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-09-03 23:51
浙ICP备14020137号-1 $mapa de visitantes$