state-management
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseState Management with React Query + Zustand
基于React Query + Zustand的状态管理
Version 1.0.0
State Management Patterns
January 2026
Note: This document provides comprehensive patterns for AI agents and LLMs working with React Query (TanStack Query) and Zustand. Optimized for automated refactoring, code generation, and state management best practices.
Comprehensive patterns for server state (React Query) and client state (Zustand). Contains 26+ rules for efficient data fetching and state management.
版本 1.0.0
状态管理模式
2026年1月
注意: 本文档为AI Agent和大语言模型提供了使用React Query(TanStack Query)与Zustand的综合模式。针对自动化重构、代码生成和状态管理最佳实践进行了优化。
涵盖服务端状态(React Query)与客户端状态(Zustand)的综合模式。包含26+条高效数据获取与状态管理的规则。
When to Apply
适用场景
Reference these guidelines when:
- Fetching data from APIs
- Managing server state and caching
- Handling mutations and optimistic updates
- Creating client-side stores
- Combining React Query with Zustand
在以下场景中参考本指南:
- 从API获取数据
- 管理服务端状态与缓存
- 处理变更与乐观更新
- 创建客户端存储
- 结合使用React Query与Zustand
Rule Categories by Priority
按优先级划分的规则类别
| Priority | Category | Impact | Prefix |
|---|---|---|---|
| 1 | React Query Basics | CRITICAL | |
| 2 | Zustand Store Patterns | CRITICAL | |
| 3 | Caching & Invalidation | HIGH | |
| 4 | Mutations & Updates | HIGH | |
| 5 | Optimistic Updates | MEDIUM | |
| 6 | DevTools & Debugging | MEDIUM | |
| 7 | Advanced Patterns | LOW | |
| 优先级 | 类别 | 影响程度 | 前缀 |
|---|---|---|---|
| 1 | React Query基础 | 关键 | |
| 2 | Zustand存储模式 | 关键 | |
| 3 | 缓存与失效 | 高 | |
| 4 | 变更与更新 | 高 | |
| 5 | 乐观更新 | 中 | |
| 6 | 开发工具与调试 | 中 | |
| 7 | 高级模式 | 低 | |
Quick Reference
快速参考
1. React Query Basics (CRITICAL)
1. React Query基础(关键)
- - QueryClient and Provider setup
rq-setup - - Basic useQuery patterns
rq-usequery - - Query key organization
rq-querykeys - - Handle loading and error states
rq-loading-error - - Conditional queries
rq-enabled
- - QueryClient与Provider配置
rq-setup - - 基础useQuery模式
rq-usequery - - 查询键组织
rq-querykeys - - 处理加载与错误状态
rq-loading-error - - 条件查询
rq-enabled
2. Zustand Store Patterns (CRITICAL)
2. Zustand存储模式(关键)
- - Create basic store
zs-create-store - - TypeScript store patterns
zs-typescript - - Efficient selectors
zs-selectors - - Action patterns
zs-actions - - Persist state to storage
zs-persist
- - 创建基础存储
zs-create-store - - TypeScript存储模式
zs-typescript - - 高效选择器
zs-selectors - - 操作模式
zs-actions - - 将状态持久化到存储
zs-persist
3. Caching & Invalidation (HIGH)
3. 缓存与失效(高)
- - Configure stale time
cache-stale-time - - Configure garbage collection
cache-gc-time - - Invalidate queries
cache-invalidation - - Prefetch data
cache-prefetch - - Set initial data
cache-initial-data
- - 配置过期时间
cache-stale-time - - 配置垃圾回收时间
cache-gc-time - - 失效查询
cache-invalidation - - 预取数据
cache-prefetch - - 设置初始数据
cache-initial-data
4. Mutations & Updates (HIGH)
4. 变更与更新(高)
- - Basic useMutation
mut-usemutation - - onSuccess, onError callbacks
mut-callbacks - - Invalidate after mutation
mut-invalidate - - Direct cache updates
mut-update-cache
- - 基础useMutation
mut-usemutation - - onSuccess、onError回调
mut-callbacks - - 变更后失效查询
mut-invalidate - - 直接更新缓存
mut-update-cache
5. Optimistic Updates (MEDIUM)
5. 乐观更新(中)
- - Basic optimistic updates
opt-basic - - Rollback on error
opt-rollback - - Use mutation variables
opt-variables
- - 基础乐观更新
opt-basic - - 错误时回滚
opt-rollback - - 使用变更变量
opt-variables
6. DevTools & Debugging (MEDIUM)
6. 开发工具与调试(中)
- - React Query DevTools
dev-react-query - - Zustand DevTools
dev-zustand - - Debug strategies
dev-debugging
- - React Query开发工具
dev-react-query - - Zustand开发工具
dev-zustand - - 调试策略
dev-debugging
7. Advanced Patterns (LOW)
7. 高级模式(低)
- - Infinite scrolling
adv-infinite-queries - - Parallel requests
adv-parallel-queries - - Dependent queries
adv-dependent-queries - - Combine RQ with Zustand
adv-query-zustand
- - 无限滚动
adv-infinite-queries - - 并行请求
adv-parallel-queries - - 依赖查询
adv-dependent-queries - - 结合React Query与Zustand
adv-query-zustand
React Query Patterns
React Query模式
Setup
配置
tsx
// lib/queryClient.ts
import { QueryClient } from '@tanstack/react-query'
export const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 1000 * 60 * 5, // 5 minutes
gcTime: 1000 * 60 * 30, // 30 minutes (formerly cacheTime)
retry: 1,
refetchOnWindowFocus: false,
},
},
})
// App.tsx
import { QueryClientProvider } from '@tanstack/react-query'
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
import { queryClient } from './lib/queryClient'
function App() {
return (
<QueryClientProvider client={queryClient}>
<Router />
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
)
}tsx
// lib/queryClient.ts
import { QueryClient } from '@tanstack/react-query'
export const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 1000 * 60 * 5, // 5分钟
gcTime: 1000 * 60 * 30, // 30分钟(原cacheTime)
retry: 1,
refetchOnWindowFocus: false,
},
},
})
// App.tsx
import { QueryClientProvider } from '@tanstack/react-query'
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
import { queryClient } from './lib/queryClient'
function App() {
return (
<QueryClientProvider client={queryClient}>
<Router />
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
)
}Query Keys Factory
查询键工厂
tsx
// lib/queryKeys.ts
export const queryKeys = {
// All posts
posts: {
all: ['posts'] as const,
lists: () => [...queryKeys.posts.all, 'list'] as const,
list: (filters: PostFilters) =>
[...queryKeys.posts.lists(), filters] as const,
details: () => [...queryKeys.posts.all, 'detail'] as const,
detail: (id: number) => [...queryKeys.posts.details(), id] as const,
},
// All users
users: {
all: ['users'] as const,
detail: (id: number) => [...queryKeys.users.all, id] as const,
posts: (userId: number) => [...queryKeys.users.all, userId, 'posts'] as const,
},
}tsx
// lib/queryKeys.ts
export const queryKeys = {
// 所有文章
posts: {
all: ['posts'] as const,
lists: () => [...queryKeys.posts.all, 'list'] as const,
list: (filters: PostFilters) =>
[...queryKeys.posts.lists(), filters] as const,
details: () => [...queryKeys.posts.all, 'detail'] as const,
detail: (id: number) => [...queryKeys.posts.details(), id] as const,
},
// 所有用户
users: {
all: ['users'] as const,
detail: (id: number) => [...queryKeys.users.all, id] as const,
posts: (userId: number) => [...queryKeys.users.all, userId, 'posts'] as const,
},
}useQuery Hook
useQuery钩子
tsx
// hooks/usePosts.ts
import { useQuery } from '@tanstack/react-query'
import { queryKeys } from '@/lib/queryKeys'
import { fetchPosts, fetchPost } from '@/api/posts'
export function usePosts(filters?: PostFilters) {
return useQuery({
queryKey: queryKeys.posts.list(filters ?? {}),
queryFn: () => fetchPosts(filters),
})
}
export function usePost(id: number) {
return useQuery({
queryKey: queryKeys.posts.detail(id),
queryFn: () => fetchPost(id),
enabled: !!id, // Only run if id exists
})
}
// Usage in component
function PostList() {
const { data: posts, isLoading, error } = usePosts()
if (isLoading) return <Spinner />
if (error) return <Error message={error.message} />
return (
<ul>
{posts?.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
)
}tsx
// hooks/usePosts.ts
import { useQuery } from '@tanstack/react-query'
import { queryKeys } from '@/lib/queryKeys'
import { fetchPosts, fetchPost } from '@/api/posts'
export function usePosts(filters?: PostFilters) {
return useQuery({
queryKey: queryKeys.posts.list(filters ?? {}),
queryFn: () => fetchPosts(filters),
})
}
export function usePost(id: number) {
return useQuery({
queryKey: queryKeys.posts.detail(id),
queryFn: () => fetchPost(id),
enabled: !!id, // 仅当id存在时运行
})
}
// 在组件中使用
function PostList() {
const { data: posts, isLoading, error } = usePosts()
if (isLoading) return <Spinner />
if (error) return <Error message={error.message} />
return (
<ul>
{posts?.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
)
}useMutation Hook
useMutation钩子
tsx
// hooks/useCreatePost.ts
import { useMutation, useQueryClient } from '@tanstack/react-query'
import { queryKeys } from '@/lib/queryKeys'
import { createPost } from '@/api/posts'
export function useCreatePost() {
const queryClient = useQueryClient()
return useMutation({
mutationFn: createPost,
onSuccess: (newPost) => {
// Invalidate and refetch posts list
queryClient.invalidateQueries({
queryKey: queryKeys.posts.lists(),
})
},
onError: (error) => {
console.error('Failed to create post:', error)
},
})
}
// Usage
function CreatePostForm() {
const { mutate, isPending } = useCreatePost()
const handleSubmit = (data: CreatePostData) => {
mutate(data)
}
return (
<form onSubmit={handleSubmit}>
{/* form fields */}
<button disabled={isPending}>
{isPending ? 'Creating...' : 'Create'}
</button>
</form>
)
}tsx
// hooks/useCreatePost.ts
import { useMutation, useQueryClient } from '@tanstack/react-query'
import { queryKeys } from '@/lib/queryKeys'
import { createPost } from '@/api/posts'
export function useCreatePost() {
const queryClient = useQueryClient()
return useMutation({
mutationFn: createPost,
onSuccess: (newPost) => {
// 失效并重新获取文章列表
queryClient.invalidateQueries({
queryKey: queryKeys.posts.lists(),
})
},
onError: (error) => {
console.error('创建文章失败:', error)
},
})
}
// 使用示例
function CreatePostForm() {
const { mutate, isPending } = useCreatePost()
const handleSubmit = (data: CreatePostData) => {
mutate(data)
}
return (
<form onSubmit={handleSubmit}>
{/* 表单字段 */}
<button disabled={isPending}>
{isPending ? '创建中...' : '创建'}
</button>
</form>
)
}Optimistic Updates
乐观更新
tsx
export function useUpdatePost() {
const queryClient = useQueryClient()
return useMutation({
mutationFn: updatePost,
onMutate: async (updatedPost) => {
// Cancel outgoing refetches
await queryClient.cancelQueries({
queryKey: queryKeys.posts.detail(updatedPost.id),
})
// Snapshot previous value
const previousPost = queryClient.getQueryData(
queryKeys.posts.detail(updatedPost.id)
)
// Optimistically update
queryClient.setQueryData(
queryKeys.posts.detail(updatedPost.id),
updatedPost
)
return { previousPost }
},
onError: (err, updatedPost, context) => {
// Rollback on error
queryClient.setQueryData(
queryKeys.posts.detail(updatedPost.id),
context?.previousPost
)
},
onSettled: (data, error, variables) => {
// Refetch after settle
queryClient.invalidateQueries({
queryKey: queryKeys.posts.detail(variables.id),
})
},
})
}tsx
export function useUpdatePost() {
const queryClient = useQueryClient()
return useMutation({
mutationFn: updatePost,
onMutate: async (updatedPost) => {
// 取消正在进行的重新获取
await queryClient.cancelQueries({
queryKey: queryKeys.posts.detail(updatedPost.id),
})
// 快照之前的值
const previousPost = queryClient.getQueryData(
queryKeys.posts.detail(updatedPost.id)
)
// 乐观更新
queryClient.setQueryData(
queryKeys.posts.detail(updatedPost.id),
updatedPost
)
return { previousPost }
},
onError: (err, updatedPost, context) => {
// 错误时回滚
queryClient.setQueryData(
queryKeys.posts.detail(updatedPost.id),
context?.previousPost
)
},
onSettled: (data, error, variables) => {
// 完成后重新获取
queryClient.invalidateQueries({
queryKey: queryKeys.posts.detail(variables.id),
})
},
})
}Zustand Patterns
Zustand模式
Basic Store
基础存储
tsx
// stores/useCounterStore.ts
import { create } from 'zustand'
interface CounterState {
count: number
increment: () => void
decrement: () => void
reset: () => void
}
export const useCounterStore = create<CounterState>((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
reset: () => set({ count: 0 }),
}))
// Usage
function Counter() {
const { count, increment, decrement } = useCounterStore()
return (
<div>
<span>{count}</span>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
</div>
)
}tsx
// stores/useCounterStore.ts
import { create } from 'zustand'
interface CounterState {
count: number
increment: () => void
decrement: () => void
reset: () => void
}
export const useCounterStore = create<CounterState>((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
reset: () => set({ count: 0 }),
}))
// 使用示例
function Counter() {
const { count, increment, decrement } = useCounterStore()
return (
<div>
<span>{count}</span>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
</div>
)
}Store with TypeScript and Middleware
结合TypeScript与中间件的存储
tsx
// stores/useAuthStore.ts
import { create } from 'zustand'
import { persist, devtools } from 'zustand/middleware'
interface User {
id: number
name: string
email: string
}
interface AuthState {
user: User | null
token: string | null
isAuthenticated: boolean
login: (user: User, token: string) => void
logout: () => void
}
export const useAuthStore = create<AuthState>()(
devtools(
persist(
(set) => ({
user: null,
token: null,
isAuthenticated: false,
login: (user, token) =>
set({
user,
token,
isAuthenticated: true,
}),
logout: () =>
set({
user: null,
token: null,
isAuthenticated: false,
}),
}),
{
name: 'auth-storage',
partialize: (state) => ({
user: state.user,
token: state.token,
isAuthenticated: state.isAuthenticated,
}),
}
)
)
)tsx
// stores/useAuthStore.ts
import { create } from 'zustand'
import { persist, devtools } from 'zustand/middleware'
interface User {
id: number
name: string
email: string
}
interface AuthState {
user: User | null
token: string | null
isAuthenticated: boolean
login: (user: User, token: string) => void
logout: () => void
}
export const useAuthStore = create<AuthState>()(
devtools(
persist(
(set) => ({
user: null,
token: null,
isAuthenticated: false,
login: (user, token) =>
set({
user,
token,
isAuthenticated: true,
}),
logout: () =>
set({
user: null,
token: null,
isAuthenticated: false,
}),
}),
{
name: 'auth-storage',
partialize: (state) => ({
user: state.user,
token: state.token,
isAuthenticated: state.isAuthenticated,
}),
}
)
)
)Selectors for Performance
性能优化选择器
tsx
// Use selectors to prevent unnecessary re-renders
function UserName() {
// Only re-renders when user.name changes
const name = useAuthStore((state) => state.user?.name)
return <span>{name}</span>
}
// Multiple selectors
function UserInfo() {
const user = useAuthStore((state) => state.user)
const isAuthenticated = useAuthStore((state) => state.isAuthenticated)
if (!isAuthenticated) return <LoginButton />
return <span>{user?.name}</span>
}tsx
// 使用选择器避免不必要的重渲染
function UserName() {
// 仅当user.name变化时重渲染
const name = useAuthStore((state) => state.user?.name)
return <span>{name}</span>
}
// 多选择器示例
function UserInfo() {
const user = useAuthStore((state) => state.user)
const isAuthenticated = useAuthStore((state) => state.isAuthenticated)
if (!isAuthenticated) return <LoginButton />
return <span>{user?.name}</span>
}Combining React Query + Zustand
结合React Query + Zustand
tsx
// Server state: React Query (what comes from API)
const { data: posts } = usePosts()
// Client state: Zustand (UI state)
const { selectedPostId, selectPost } = useUIStore()
// Use together
const selectedPost = posts?.find((p) => p.id === selectedPostId)tsx
// 服务端状态:React Query(来自API的数据)
const { data: posts } = usePosts()
// 客户端状态:Zustand(UI状态)
const { selectedPostId, selectPost } = useUIStore()
// 结合使用
const selectedPost = posts?.find((p) => p.id === selectedPostId)How to Use
使用方法
Read individual rule files for detailed explanations and code examples:
rules/rq-usequery.md
rules/zs-create-store.md
rules/cache-invalidation.md阅读单个规则文件获取详细说明与代码示例:
rules/rq-usequery.md
rules/zs-create-store.md
rules/cache-invalidation.mdReferences
参考资料
React Query (TanStack Query)
React Query (TanStack Query)
Zustand
Zustand
License
许可证
This skill is provided as-is for educational and development purposes. React Query is MIT licensed by TanStack. Zustand is MIT licensed by Poimandres (pmnd.rs).
本技能仅供教育与开发使用。React Query由TanStack以MIT许可证发布。Zustand由Poimandres(pmnd.rs)以MIT许可证发布。