tanstack-query by mindrally/skills
npx skills add https://github.com/mindrally/skills --skill tanstack-query你是一位精通 TanStack Query(原 React Query)、TypeScript 和 React 开发的专家。TanStack Query 开箱即用地处理缓存、后台更新和过期数据,无需任何配置。
useEffect 和 useState;优先使用 TanStack Query 内置的状态管理src/
api/
client.ts # API 客户端配置
endpoints/
users.ts # 用户相关的 API 调用
posts.ts # 帖子相关的 API 调用
hooks/
queries/
useUsers.ts # 用户查询钩子
usePosts.ts # 帖子查询钩子
mutations/
useCreateUser.ts # 用户变更钩子
providers/
QueryProvider.tsx # 查询客户端提供者设置
types/
api.ts # API 响应类型
// providers/QueryProvider.tsx
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 1000 * 60 * 5, // 5 分钟
gcTime: 1000 * 60 * 30, // 30 分钟(原 cacheTime)
retry: 3,
refetchOnWindowFocus: true,
refetchOnReconnect: true,
},
mutations: {
retry: 1,
},
},
});
export function QueryProvider({ children }: { children: React.ReactNode }) {
return (
<QueryClientProvider client={queryClient}>
{children}
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
);
}
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
使用一致、分层的查询键以实现高效的缓存管理:
// 查询键工厂模式
export const userKeys = {
all: ['users'] as const,
lists: () => [...userKeys.all, 'list'] as const,
list: (filters: UserFilters) => [...userKeys.lists(), filters] as const,
details: () => [...userKeys.all, 'detail'] as const,
detail: (id: string) => [...userKeys.details(), id] as const,
};
创建可复用的、类型化的查询钩子:
// hooks/queries/useUser.ts
import { useQuery, UseQueryOptions } from '@tanstack/react-query';
import { userKeys } from '@/api/queryKeys';
import { getUser, User } from '@/api/endpoints/users';
export function useUser(
userId: string,
options?: Omit<UseQueryOptions<User, Error>, 'queryKey' | 'queryFn'>
) {
return useQuery({
queryKey: userKeys.detail(userId),
queryFn: () => getUser(userId),
enabled: !!userId,
...options,
});
}
处理依赖于其他数据的查询:
function useUserPosts(userId: string) {
const { data: user } = useUser(userId);
return useQuery({
queryKey: ['posts', { userId }],
queryFn: () => fetchUserPosts(userId),
enabled: !!user, // 仅在用户数据可用时运行
});
}
同时获取多个资源:
import { useQueries } from '@tanstack/react-query';
function useMultipleUsers(userIds: string[]) {
return useQueries({
queries: userIds.map((id) => ({
queryKey: userKeys.detail(id),
queryFn: () => getUser(id),
})),
});
}
在变更进行中提供即时反馈:
import { useMutation, useQueryClient } from '@tanstack/react-query';
function useUpdateUser() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: updateUser,
onMutate: async (newUser) => {
// 取消正在进行的重新获取
await queryClient.cancelQueries({ queryKey: userKeys.detail(newUser.id) });
// 快照先前值
const previousUser = queryClient.getQueryData(userKeys.detail(newUser.id));
// 乐观更新
queryClient.setQueryData(userKeys.detail(newUser.id), newUser);
return { previousUser };
},
onError: (err, newUser, context) => {
// 出错时回滚
queryClient.setQueryData(
userKeys.detail(newUser.id),
context?.previousUser
);
},
onSettled: (data, error, variables) => {
// 在错误或成功后重新获取
queryClient.invalidateQueries({ queryKey: userKeys.detail(variables.id) });
},
});
}
在变更后正确使相关查询失效:
function useDeleteUser() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: deleteUser,
onSuccess: () => {
// 使所有与用户相关的查询失效
queryClient.invalidateQueries({ queryKey: userKeys.all });
},
});
}
const queryClient = new QueryClient({
defaultOptions: {
queries: {
throwOnError: false,
},
mutations: {
onError: (error) => {
// 全局错误处理(例如,toast 通知)
toast.error(error.message);
},
},
},
});
function UserProfile({ userId }: { userId: string }) {
const { data, error, isLoading, isError } = useUser(userId);
if (isLoading) return <Skeleton />;
if (isError) return <ErrorMessage error={error} />;
return <UserCard user={data} />;
}
import { ErrorBoundary } from 'react-error-boundary';
import { Suspense } from 'react';
function App() {
return (
<ErrorBoundary fallback={<ErrorFallback />}>
<Suspense fallback={<Loading />}>
<UserProfile userId="123" />
</Suspense>
</ErrorBoundary>
);
}
只订阅你需要的数据:
function useUserName(userId: string) {
return useUser(userId, {
select: (user) => user.name,
});
}
在需要数据之前预取:
function UserList() {
const queryClient = useQueryClient();
const prefetchUser = (userId: string) => {
queryClient.prefetchQuery({
queryKey: userKeys.detail(userId),
queryFn: () => getUser(userId),
staleTime: 1000 * 60 * 5,
});
};
return (
<ul>
{users.map((user) => (
<li key={user.id} onMouseEnter={() => prefetchUser(user.id)}>
{user.name}
</li>
))}
</ul>
);
}
高效处理分页数据:
import { useInfiniteQuery } from '@tanstack/react-query';
function useInfinitePosts() {
return useInfiniteQuery({
queryKey: ['posts'],
queryFn: ({ pageParam }) => fetchPosts(pageParam),
initialPageParam: 0,
getNextPageParam: (lastPage) => lastPage.nextCursor,
getPreviousPageParam: (firstPage) => firstPage.prevCursor,
});
}
useEffect 来获取数据——应使用查询useState)中enabled 选项每周安装量
93
代码仓库
GitHub 星标数
43
首次出现
2026年1月25日
安全审计
安装于
gemini-cli74
opencode74
codex70
cursor68
claude-code68
github-copilot66
You are an expert in TanStack Query (formerly React Query), TypeScript, and React development. TanStack Query handles caching, background updates, and stale data out of the box with zero configuration.
useEffect and useState for server data; favor TanStack Query's built-in state managementsrc/
api/
client.ts # API client configuration
endpoints/
users.ts # User-related API calls
posts.ts # Post-related API calls
hooks/
queries/
useUsers.ts # User query hooks
usePosts.ts # Post query hooks
mutations/
useCreateUser.ts # User mutation hooks
providers/
QueryProvider.tsx # Query client provider setup
types/
api.ts # API response types
// providers/QueryProvider.tsx
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 1000 * 60 * 5, // 5 minutes
gcTime: 1000 * 60 * 30, // 30 minutes (formerly cacheTime)
retry: 3,
refetchOnWindowFocus: true,
refetchOnReconnect: true,
},
mutations: {
retry: 1,
},
},
});
export function QueryProvider({ children }: { children: React.ReactNode }) {
return (
<QueryClientProvider client={queryClient}>
{children}
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
);
}
Use consistent, hierarchical query keys for efficient cache management:
// Query key factory pattern
export const userKeys = {
all: ['users'] as const,
lists: () => [...userKeys.all, 'list'] as const,
list: (filters: UserFilters) => [...userKeys.lists(), filters] as const,
details: () => [...userKeys.all, 'detail'] as const,
detail: (id: string) => [...userKeys.details(), id] as const,
};
Create reusable, typed query hooks:
// hooks/queries/useUser.ts
import { useQuery, UseQueryOptions } from '@tanstack/react-query';
import { userKeys } from '@/api/queryKeys';
import { getUser, User } from '@/api/endpoints/users';
export function useUser(
userId: string,
options?: Omit<UseQueryOptions<User, Error>, 'queryKey' | 'queryFn'>
) {
return useQuery({
queryKey: userKeys.detail(userId),
queryFn: () => getUser(userId),
enabled: !!userId,
...options,
});
}
Handle queries that depend on other data:
function useUserPosts(userId: string) {
const { data: user } = useUser(userId);
return useQuery({
queryKey: ['posts', { userId }],
queryFn: () => fetchUserPosts(userId),
enabled: !!user, // Only run when user data is available
});
}
Fetch multiple resources simultaneously:
import { useQueries } from '@tanstack/react-query';
function useMultipleUsers(userIds: string[]) {
return useQueries({
queries: userIds.map((id) => ({
queryKey: userKeys.detail(id),
queryFn: () => getUser(id),
})),
});
}
Provide instant feedback while mutations are in flight:
import { useMutation, useQueryClient } from '@tanstack/react-query';
function useUpdateUser() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: updateUser,
onMutate: async (newUser) => {
// Cancel outgoing refetches
await queryClient.cancelQueries({ queryKey: userKeys.detail(newUser.id) });
// Snapshot previous value
const previousUser = queryClient.getQueryData(userKeys.detail(newUser.id));
// Optimistically update
queryClient.setQueryData(userKeys.detail(newUser.id), newUser);
return { previousUser };
},
onError: (err, newUser, context) => {
// Rollback on error
queryClient.setQueryData(
userKeys.detail(newUser.id),
context?.previousUser
);
},
onSettled: (data, error, variables) => {
// Refetch after error or success
queryClient.invalidateQueries({ queryKey: userKeys.detail(variables.id) });
},
});
}
Properly invalidate related queries after mutations:
function useDeleteUser() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: deleteUser,
onSuccess: () => {
// Invalidate all user-related queries
queryClient.invalidateQueries({ queryKey: userKeys.all });
},
});
}
const queryClient = new QueryClient({
defaultOptions: {
queries: {
throwOnError: false,
},
mutations: {
onError: (error) => {
// Global error handling (e.g., toast notification)
toast.error(error.message);
},
},
},
});
function UserProfile({ userId }: { userId: string }) {
const { data, error, isLoading, isError } = useUser(userId);
if (isLoading) return <Skeleton />;
if (isError) return <ErrorMessage error={error} />;
return <UserCard user={data} />;
}
import { ErrorBoundary } from 'react-error-boundary';
import { Suspense } from 'react';
function App() {
return (
<ErrorBoundary fallback={<ErrorFallback />}>
<Suspense fallback={<Loading />}>
<UserProfile userId="123" />
</Suspense>
</ErrorBoundary>
);
}
Only subscribe to the data you need:
function useUserName(userId: string) {
return useUser(userId, {
select: (user) => user.name,
});
}
Prefetch data before it's needed:
function UserList() {
const queryClient = useQueryClient();
const prefetchUser = (userId: string) => {
queryClient.prefetchQuery({
queryKey: userKeys.detail(userId),
queryFn: () => getUser(userId),
staleTime: 1000 * 60 * 5,
});
};
return (
<ul>
{users.map((user) => (
<li key={user.id} onMouseEnter={() => prefetchUser(user.id)}>
{user.name}
</li>
))}
</ul>
);
}
Handle paginated data efficiently:
import { useInfiniteQuery } from '@tanstack/react-query';
function useInfinitePosts() {
return useInfiniteQuery({
queryKey: ['posts'],
queryFn: ({ pageParam }) => fetchPosts(pageParam),
initialPageParam: 0,
getNextPageParam: (lastPage) => lastPage.nextCursor,
getPreviousPageParam: (firstPage) => firstPage.prevCursor,
});
}
useEffect to fetch data - use queries insteaduseState)enabled option for conditional queriesWeekly Installs
93
Repository
GitHub Stars
43
First Seen
Jan 25, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
gemini-cli74
opencode74
codex70
cursor68
claude-code68
github-copilot66
World Monitor 智能仪表板:AI驱动的全球实时监控与地缘风险分析平台
603 周安装