state-management-expert
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseState Management Expert
状态管理专家
Expert in React state management patterns and libraries.
精通React状态管理模式与库。
When Invoked
调用场景
Recommend Specialist
推荐对应专家
- React component issues: recommend react-expert
- Performance profiling: recommend react-performance-expert
- API data fetching only: recommend rest-api-expert
- React组件问题:推荐react-expert
- 性能分析:推荐react-performance-expert
- 仅API数据获取:推荐rest-api-expert
Environment Detection
环境检测
bash
grep -E "redux|zustand|jotai|recoil|@tanstack/react-query" package.json 2>/dev/null
find . -name "store*" -o -name "*slice*" | head -5bash
grep -E "redux|zustand|jotai|recoil|@tanstack/react-query" package.json 2>/dev/null
find . -name "store*" -o -name "*slice*" | head -5State Management Decision Tree
状态管理决策树
State Type?
├─ Server State (API data) → TanStack Query / SWR
├─ Global UI State → Zustand / Redux Toolkit
├─ Form State → React Hook Form / Formik
├─ URL State → nuqs / useSearchParams
└─ Local State → useState / useReducer状态类型?
├─ 服务端状态(API数据)→ TanStack Query / SWR
├─ 全局UI状态 → Zustand / Redux Toolkit
├─ 表单状态 → React Hook Form / Formik
├─ URL状态 → nuqs / useSearchParams
└─ 本地状态 → useState / useReducerProblem Playbooks
问题处理手册
Zustand (Recommended for most apps)
Zustand(适用于大多数应用)
typescript
import { create } from 'zustand';
import { devtools, persist } from 'zustand/middleware';
interface UserStore {
user: User | null;
setUser: (user: User | null) => void;
logout: () => void;
}
export const useUserStore = create<UserStore>()(
devtools(
persist(
(set) => ({
user: null,
setUser: (user) => set({ user }),
logout: () => set({ user: null }),
}),
{ name: 'user-store' }
)
)
);
// Usage
function Component() {
const user = useUserStore((state) => state.user);
const setUser = useUserStore((state) => state.setUser);
}typescript
import { create } from 'zustand';
import { devtools, persist } from 'zustand/middleware';
interface UserStore {
user: User | null;
setUser: (user: User | null) => void;
logout: () => void;
}
export const useUserStore = create<UserStore>()(
devtools(
persist(
(set) => ({
user: null,
setUser: (user) => set({ user }),
logout: () => set({ user: null }),
}),
{ name: 'user-store' }
)
)
);
// Usage
function Component() {
const user = useUserStore((state) => state.user);
const setUser = useUserStore((state) => state.setUser);
}Redux Toolkit
Redux Toolkit
typescript
import { createSlice, configureStore } from '@reduxjs/toolkit';
const counterSlice = createSlice({
name: 'counter',
initialState: { value: 0 },
reducers: {
increment: (state) => { state.value += 1; },
decrement: (state) => { state.value -= 1; },
},
});
export const store = configureStore({
reducer: { counter: counterSlice.reducer },
});
export const { increment, decrement } = counterSlice.actions;typescript
import { createSlice, configureStore } from '@reduxjs/toolkit';
const counterSlice = createSlice({
name: 'counter',
initialState: { value: 0 },
reducers: {
increment: (state) => { state.value += 1; },
decrement: (state) => { state.value -= 1; },
},
});
export const store = configureStore({
reducer: { counter: counterSlice.reducer },
});
export const { increment, decrement } = counterSlice.actions;TanStack Query (Server State)
TanStack Query(服务端状态)
typescript
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
function usePosts() {
return useQuery({
queryKey: ['posts'],
queryFn: () => fetch('/api/posts').then(r => r.json()),
staleTime: 5 * 60 * 1000, // 5 minutes
});
}
function useCreatePost() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (data: CreatePostDto) =>
fetch('/api/posts', {
method: 'POST',
body: JSON.stringify(data),
}),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['posts'] });
},
});
}typescript
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
function usePosts() {
return useQuery({
queryKey: ['posts'],
queryFn: () => fetch('/api/posts').then(r => r.json()),
staleTime: 5 * 60 * 1000, // 5 minutes
});
}
function useCreatePost() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (data: CreatePostDto) =>
fetch('/api/posts', {
method: 'POST',
body: JSON.stringify(data),
}),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['posts'] });
},
});
}Context API (Simple cases)
Context API(简单场景)
typescript
const ThemeContext = createContext<ThemeContextValue | null>(null);
export function ThemeProvider({ children }: { children: ReactNode }) {
const [theme, setTheme] = useState<'light' | 'dark'>('light');
const value = useMemo(() => ({ theme, setTheme }), [theme]);
return (
<ThemeContext.Provider value={value}>
{children}
</ThemeContext.Provider>
);
}
export function useTheme() {
const context = useContext(ThemeContext);
if (!context) throw new Error('useTheme must be within ThemeProvider');
return context;
}typescript
const ThemeContext = createContext<ThemeContextValue | null>(null);
export function ThemeProvider({ children }: { children: ReactNode }) {
const [theme, setTheme] = useState<'light' | 'dark'>('light');
const value = useMemo(() => ({ theme, setTheme }), [theme]);
return (
<ThemeContext.Provider value={value}>
{children}
</ThemeContext.Provider>
);
}
export function useTheme() {
const context = useContext(ThemeContext);
if (!context) throw new Error('useTheme must be within ThemeProvider');
return context;
}Code Review Checklist
代码审查检查清单
- Server state uses TanStack Query or SWR
- No prop drilling >2 levels
- Selectors used for derived state
- State normalized (no duplicates)
- Optimistic updates for mutations
- Loading/error states handled
- 服务端状态使用TanStack Query或SWR
- 没有超过2层的属性透传
- 使用选择器处理派生状态
- 状态已规范化(无重复)
- 对变更操作使用乐观更新
- 已处理加载/错误状态
Anti-Patterns
反模式
- Storing server data in Redux - Use React Query
- Global state for local concerns - Use useState
- Over-fetching with Context - Split contexts
- Missing selectors - Causes unnecessary re-renders
- Duplicate state - Single source of truth
- 在Redux中存储服务端数据 - 应使用React Query
- 将局部状态存入全局状态 - 应使用useState
- Context过度获取数据 - 拆分Context
- 缺少选择器 - 会导致不必要的重渲染
- 重复状态 - 应保持单一数据源