
关于
掌握现代 React 状态管理,包括 Redux Toolkit、Zustand、Jotai 和 React Query。适用于设置全局状态、管理服务端状态或选择状态管理方案。
name: react-state-management description: "掌握现代 React 状态管理,包括 Redux Toolkit、Zustand、Jotai 和 React Query。适用于设置全局状态、管理服务器状态或选择状态管理方案。" risk: unknown source: community date_added: "2026-02-27"
React 状态管理
现代 React 状态管理模式的全面指南,从本地组件状态到全局存储和服务器状态同步。
不适用场景
- 任务与 React 状态管理无关
- 需要此范围之外的其他领域或工具
使用说明
- 明确目标、约束和所需输入。
- 应用相关最佳实践并验证结果。
- 提供可操作的步骤和验证方法。
- 如需详细示例,请打开
resources/implementation-playbook.md。
适用场景
- 在 React 应用中设置全局状态管理
- 在 Redux Toolkit、Zustand 或 Jotai 之间做选择
- 使用 React Query 或 SWR 管理服务器状态
- 实现乐观更新
- 调试状态相关问题
- 从旧版 Redux 迁移到现代模式
核心概念
1. 状态分类
| 类型 | 描述 | 解决方案 | |------|------|----------| | 本地状态 | 组件特定的 UI 状态 | useState, useReducer | | 全局状态 | 跨组件共享 | Redux Toolkit, Zustand, Jotai | | 服务器状态 | 远程数据、缓存 | React Query, SWR, RTK Query | | URL 状态 | 路由参数、搜索 | React Router, nuqs | | 表单状态 | 输入值、验证 | React Hook Form, Formik |
2. 选择标准
小型应用,简单状态 → Zustand 或 Jotai
大型应用,复杂状态 → Redux Toolkit
大量服务器交互 → React Query + 轻量客户端状态
原子化/细粒度更新 → Jotai
快速开始
Zustand(最简单)
// store/useStore.ts
import { create } from 'zustand'
import { devtools, persist } from 'zustand/middleware'
interface AppState {
user: User | null
theme: 'light' | 'dark'
setUser: (user: User | null) => void
toggleTheme: () => void
}
export const useStore = create<AppState>()(
devtools(
persist(
(set) => ({
user: null,
theme: 'light',
setUser: (user) => set({ user }),
toggleTheme: () => set((state) => ({
theme: state.theme === 'light' ? 'dark' : 'light'
})),
}),
{ name: 'app-storage' }
)
)
)
// 在组件中使用
function Header() {
const { user, theme, toggleTheme } = useStore()
return (
<header className={theme}>
{user?.name}
<button onClick={toggleTheme}>Toggle Theme</button>
</header>
)
}
模式
模式 1:Redux Toolkit + TypeScript
// store/index.ts
import { configureStore } from '@reduxjs/toolkit'
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'
import userReducer from './slices/userSlice'
import cartReducer from './slices/cartSlice'
export const store = configureStore({
reducer: {
user: userReducer,
cart: cartReducer,
},
})
export type RootState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatch
export const useAppDispatch: () => AppDispatch = useDispatch
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
// store/slices/userSlice.ts
import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit'
interface UserState {
data: User | null
status: 'idle' | 'loading' | 'succeeded' | 'failed'
error: string | null
}
const initialState: UserState = {
data: null,
status: 'idle',
error: null,
}
export const fetchUser = createAsyncThunk(
'user/fetchUser',
async (userId: string) => {
const response = await api.getUser(userId)
return response.data
}
)
const userSlice = createSlice({
name: 'user',
initialState,
reducers: {
setUser: (state, action: PayloadAction<User>) => {
state.data = action.payload
},
clearUser: (state) => {
state.data = null
},
},
extraReducers: (builder) => {
builder
.addCase(fetchUser.pending, (state) => {
state.status = 'loading'
})
.addCase(fetchUser.fulfilled, (state, action) => {
state.status = 'succeeded'
state.data = action.payload
})
.addCase(fetchUser.rejected, (state, action) => {
state.status = 'failed'
state.error = action.error.message ?? null
})
},
})
export const { setUser, clearUser } = userSlice.actions
export default userSlice.reducer
模式 2:React Query 服务器状态
// hooks/useUsers.ts
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
export function useUsers() {
return useQuery({
queryKey: ['users'],
queryFn: () => api.getUsers(),
staleTime: 5 * 60 * 1000, // 5 分钟
})
}
export function useUpdateUser() {
const queryClient = useQueryClient()
return useMutation({
mutationFn: (user: User) => api.updateUser(user),
// 乐观更新
onMutate: async (newUser) => {
await queryClient.cancelQueries({ queryKey: ['users'] })
const previous = queryClient.getQueryData(['users'])
queryClient.setQueryData(['users'], (old: User[]) =>
old.map(u => u.id === newUser.id ? newUser : u)
)
return { previous }
},
onError: (err, newUser, context) => {
queryClient.setQueryData(['users'], context?.previous)
},
onSettled: () => {
queryClient.invalidateQueries({ queryKey: ['users'] })
},
})
}
模式 3:Jotai 原子化状态
// atoms/index.ts
import { atom } from 'jotai'
import { atomWithStorage } from 'jotai/utils'
// 基础原子
export const countAtom = atom(0)
// 派生原子
export const doubleCountAtom = atom((get) => get(countAtom) * 2)
// 可写派生原子
export const incrementAtom = atom(
null,
(get, set) => set(countAtom, get(countAtom) + 1)
)
// 持久化原子
export const themeAtom = atomWithStorage('theme', 'light')
// 异步原子
export const userAtom = atom(async () => {
const response = await fetch('/api/user')
return response.json()
})
最佳实践
- 从最简单的方案开始,按需扩展
- 服务器状态和客户端状态分开管理
- 使用 TypeScript 确保类型安全
- 避免过度使用全局状态——大多数状态应该是本地的
- 使用 DevTools 调试状态变化
- 为状态逻辑编写单元测试
限制
- 仅在任务明确匹配上述范围时使用此技能。
- 不要将输出视为环境特定验证、测试或专家审查的替代品。
- 如果缺少所需输入、权限、安全边界或成功标准,请停下来寻求澄清。
兼容工具
Claude CodeCursor
标签
前端开发