一键导入
tanstack-query
TanStack Query v5 patterns for data fetching, mutations, and cache management. Use when writing queries, mutations, or working with server state.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
TanStack Query v5 patterns for data fetching, mutations, and cache management. Use when writing queries, mutations, or working with server state.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Code review of current PR/commit changes against project coding standards. Use when the user asks for a code review or mentions reviewing changes.
Reference for the Tangle component YAML specification format
Guidelines for building well-structured, maintainable ML pipelines in Tangle
Analyzes merged PRs from the past week, identifies user-facing changes, and opens a draft PR to the TangleML/website docs repo with updated documentation. Use when running the weekly documentation sync, or when the user invokes /docs-update.
React and React Compiler patterns for this project. Use when writing React components, hooks, providers, or working with React Compiler compatibility.
Run validation and testing commands for the project. Use when the user asks to validate, lint, typecheck, or run tests.
| 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. |
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.
Use hierarchical array-based keys. For domains with multiple related queries, use a query key factory:
// Query key factory pattern (preferred for grouped queries)
export const SecretsQueryKeys = {
All: () => ["secrets"] as const,
Id: (id: string) => ["secrets", id] as const,
} as const;
// Simple keys for standalone queries
queryKey: ["pipeline-run", rootExecutionId];
queryKey: ["execution-details", rootExecutionId];
queryKey: ["component", "hydrate", componentQueryKey];
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,
});
}
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;
}
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),
});
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"] });
},
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 invalidationqueryClient.fetchQuery() — direct fetch in non-hook contexts (e.g., class-based libraries)queryClient.getQueryData() — cache reading without triggering refetchqueryClient.ensureQueryData() — fetch-if-not-cached for recursive/dependent dataMatch 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.
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;
},
.catch(() => undefined) for controlled fallbacks in queryFnonError with toast notifications in mutationsComponentHydrationError)src/services/src/hooks/ or co-located in component directoriestypes.ts in the feature folder)src/providers/