状态管理顾问Skill state-management-advisor

这个技能专注于React应用中的状态管理,帮助开发者选择和实施合适的解决方案,包括Context、Zustand、Redux Toolkit、TanStack Query和Jotai,用于处理本地状态、全局状态和服务器状态。关键词:React状态管理,全局状态管理,服务器状态管理,前端开发。

前端开发 0 次安装 0 次浏览 更新于 3/9/2026

名称: 状态管理顾问 描述: 选择并实施React状态管理解决方案,包括Context、Zustand、Redux Toolkit、TanStack Query和Jotai。用于在React应用中选择状态管理、实施全局状态或管理服务器状态时使用。

状态管理顾问

选择并实施适用于React应用的正确状态管理解决方案。

快速开始

默认使用本地状态,Context用于简单全局状态,Zustand用于复杂客户端状态,TanStack Query用于服务器状态。

说明

决策树

从这里开始:

  1. 是否是服务器数据(来自API)? → 使用TanStack Query
  2. 是否仅在一个组件中使用? → 使用useState
  3. 是否是简单全局状态(主题、认证)? → 使用Context
  4. 是否是复杂客户端状态? → 使用Zustand或Redux Toolkit

本地状态(useState)

用于组件特定状态。

基本用法:

function Counter() {
  const [count, setCount] = useState(0);
  
  return (
    <button onClick={() => setCount(count + 1)}>
      计数: {count}
    </button>
  );
}

使用对象:

function Form() {
  const [formData, setFormData] = useState({
    name: '',
    email: ''
  });
  
  const handleChange = (field: string, value: string) => {
    setFormData(prev => ({ ...prev, [field]: value }));
  };
  
  return (
    <form>
      <input
        value={formData.name}
        onChange={e => handleChange('name', e.target.value)}
      />
    </form>
  );
}

React Context

用于在组件间共享的简单全局状态。

设置:

interface AuthContextValue {
  user: User | null;
  login: (credentials: Credentials) => Promise<void>;
  logout: () => void;
}

const AuthContext = createContext<AuthContextValue | null>(null);

export function AuthProvider({ children }: { children: React.ReactNode }) {
  const [user, setUser] = useState<User | null>(null);
  
  const login = async (credentials: Credentials) => {
    const user = await api.login(credentials);
    setUser(user);
  };
  
  const logout = () => {
    setUser(null);
  };
  
  return (
    <AuthContext.Provider value={{ user, login, logout }}>
      {children}
    </AuthContext.Provider>
  );
}

export function useAuth() {
  const context = useContext(AuthContext);
  if (!context) throw new Error('useAuth必须用于AuthProvider内部');
  return context;
}

用法:

function App() {
  return (
    <AuthProvider>
      <Router />
    </AuthProvider>
  );
}

function Profile() {
  const { user, logout } = useAuth();
  return <div>{user?.name} <button onClick={logout}>登出</button></div>;
}

优化 - 拆分上下文:

// 分离频繁变化的数据
const ThemeContext = createContext<Theme>(null);
const ThemeUpdateContext = createContext<(theme: Theme) => void>(null);

function ThemeProvider({ children }) {
  const [theme, setTheme] = useState('light');
  
  return (
    <ThemeContext.Provider value={theme}>
      <ThemeUpdateContext.Provider value={setTheme}>
        {children}
      </ThemeUpdateContext.Provider>
    </ThemeContext.Provider>
  );
}

Zustand

轻量级全局状态,具有最小样板代码。

安装:

npm install zustand

基本存储:

import { create } from 'zustand';

interface CounterStore {
  count: number;
  increment: () => void;
  decrement: () => void;
}

const useCounterStore = create<CounterStore>((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
  decrement: () => set((state) => ({ count: state.count - 1 })),
}));

// 用法
function Counter() {
  const count = useCounterStore((state) => state.count);
  const increment = useCounterStore((state) => state.increment);
  
  return <button onClick={increment}>计数: {count}</button>;
}

异步操作:

interface UserStore {
  users: User[];
  loading: boolean;
  fetchUsers: () => Promise<void>;
}

const useUserStore = create<UserStore>((set) => ({
  users: [],
  loading: false,
  fetchUsers: async () => {
    set({ loading: true });
    const users = await api.fetchUsers();
    set({ users, loading: false });
  },
}));

中间件:

import { persist } from 'zustand/middleware';

const useStore = create(
  persist(
    (set) => ({
      token: null,
      setToken: (token) => set({ token }),
    }),
    {
      name: 'auth-storage',
    }
  )
);

Redux Toolkit

用于具有许多交互的复杂状态。

安装:

npm install @reduxjs/toolkit react-redux

设置存储:

import { configureStore, createSlice } from '@reduxjs/toolkit';

const counterSlice = createSlice({
  name: 'counter',
  initialState: { value: 0 },
  reducers: {
    increment: (state) => {
      state.value += 1;
    },
    decrement: (state) => {
      state.value -= 1;
    },
  },
});

export const { increment, decrement } = counterSlice.actions;

export const store = configureStore({
  reducer: {
    counter: counterSlice.reducer,
  },
});

export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;

提供者:

import { Provider } from 'react-redux';

function App() {
  return (
    <Provider store={store}>
      <Router />
    </Provider>
  );
}

用法:

import { useSelector, useDispatch } from 'react-redux';

function Counter() {
  const count = useSelector((state: RootState) => state.counter.value);
  const dispatch = useDispatch();
  
  return (
    <button onClick={() => dispatch(increment())}>
      计数: {count}
    </button>
  );
}

异步与createAsyncThunk:

import { createAsyncThunk } from '@reduxjs/toolkit';

export const fetchUsers = createAsyncThunk(
  'users/fetch',
  async () => {
    const response = await api.fetchUsers();
    return response.data;
  }
);

const usersSlice = createSlice({
  name: 'users',
  initialState: { data: [], loading: false },
  reducers: {},
  extraReducers: (builder) => {
    builder
      .addCase(fetchUsers.pending, (state) => {
        state.loading = true;
      })
      .addCase(fetchUsers.fulfilled, (state, action) => {
        state.data = action.payload;
        state.loading = false;
      });
  },
});

TanStack Query(React Query)

用于服务器状态管理。

安装:

npm install @tanstack/react-query

设置:

import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

const queryClient = new QueryClient();

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <Router />
    </QueryClientProvider>
  );
}

获取数据:

import { useQuery } from '@tanstack/react-query';

function Users() {
  const { data, isLoading, error } = useQuery({
    queryKey: ['users'],
    queryFn: fetchUsers,
  });
  
  if (isLoading) return <Spinner />;
  if (error) return <Error message={error.message} />;
  
  return <UserList users={data} />;
}

突变:

import { useMutation, useQueryClient } from '@tanstack/react-query';

function CreateUser() {
  const queryClient = useQueryClient();
  
  const mutation = useMutation({
    mutationFn: createUser,
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['users'] });
    },
  });
  
  return (
    <button onClick={() => mutation.mutate({ name: 'John' })}>
      创建用户
    </button>
  );
}

带参数:

function User({ id }: { id: string }) {
  const { data } = useQuery({
    queryKey: ['user', id],
    queryFn: () => fetchUser(id),
  });
  
  return <div>{data?.name}</div>;
}

乐观更新:

const mutation = useMutation({
  mutationFn: updateUser,
  onMutate: async (newUser) => {
    await queryClient.cancelQueries({ queryKey: ['users'] });
    const previousUsers = queryClient.getQueryData(['users']);
    
    queryClient.setQueryData(['users'], (old) => [...old, newUser]);
    
    return { previousUsers };
  },
  onError: (err, newUser, context) => {
    queryClient.setQueryData(['users'], context.previousUsers);
  },
  onSettled: () => {
    queryClient.invalidateQueries({ queryKey: ['users'] });
  },
});

Jotai

原子状态管理。

安装:

npm install jotai

基本原子:

import { atom, useAtom } from 'jotai';

const countAtom = atom(0);

function Counter() {
  const [count, setCount] = useAtom(countAtom);
  
  return (
    <button onClick={() => setCount(count + 1)}>
      计数: {count}
    </button>
  );
}

派生原子:

const countAtom = atom(0);
const doubleCountAtom = atom((get) => get(countAtom) * 2);

function Display() {
  const [doubleCount] = useAtom(doubleCountAtom);
  return <div>双倍: {doubleCount}</div>;
}

异步原子:

const usersAtom = atom(async () => {
  const response = await fetch('/api/users');
  return response.json();
});

function Users() {
  const [users] = useAtom(usersAtom);
  return <UserList users={users} />;
}

比较矩阵

解决方案 最适用场景 优点 缺点
useState 本地状态 简单,内置 仅限于组件
Context 简单全局状态 内置,无依赖 可能导致重新渲染
Zustand 复杂客户端状态 最小化,快速 生态系统较小
Redux Toolkit 大型应用,团队 强大,开发工具 冗长,学习曲线
TanStack Query 服务器状态 缓存,同步 不适用于客户端状态
Jotai 原子状态 细粒度,现代 生态系统较小

常见模式

组合解决方案

TanStack Query + Zustand:

// 服务器状态使用TanStack Query
const { data: users } = useQuery(['users'], fetchUsers);

// 客户端状态使用Zustand
const selectedUserId = useStore((state) => state.selectedUserId);

Context + TanStack Query:

function AuthProvider({ children }) {
  const { data: user } = useQuery(['me'], fetchCurrentUser);
  
  return (
    <AuthContext.Provider value={{ user }}>
      {children}
    </AuthContext.Provider>
  );
}

表单状态

使用useState控制:

function Form() {
  const [values, setValues] = useState({ name: '', email: '' });
  
  const handleSubmit = (e) => {
    e.preventDefault();
    api.submit(values);
  };
  
  return (
    <form onSubmit={handleSubmit}>
      <input
        value={values.name}
        onChange={e => setValues(prev => ({ ...prev, name: e.target.value }))}
      />
    </form>
  );
}

使用表单库:

import { useForm } from 'react-hook-form';

function Form() {
  const { register, handleSubmit } = useForm();
  
  const onSubmit = (data) => api.submit(data);
  
  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register('name')} />
    </form>
  );
}

故障排除

Context导致重新渲染:

  • 拆分为多个上下文
  • 使用useMemo优化上下文值
  • 考虑改用Zustand

TanStack Query中数据过时:

  • 调整staleTime和cacheTime
  • 使用refetchInterval进行轮询
  • 突变后无效查询

Redux样板代码多:

  • 使用Redux Toolkit(而非传统Redux)
  • 使用createSlice创建reducer
  • 使用createAsyncThunk处理异步

状态更新不反映:

  • 检查是否直接突变状态
  • 使用函数式更新
  • 验证useEffect中的依赖项