
2026年React状态管理:Context vs Zustand vs Redux Toolkit
“我应该用Context、Zustand还是Redux?”这是React开发者最常问的问题之一。到了2026年,生态系统已经成熟,答案也更加清晰。以下是一个全面的比较。
状态管理格局
| 方案 | 包体积 | 复杂度 | 开发者工具 | 最佳适用场景 |
|---|---|---|---|---|
| React Context | 0KB(内置) | 低 | 基础 | 主题、认证、本地化 |
| Zustand | 1.1KB | 低 | Chrome扩展 | 大多数应用 |
| Redux Toolkit | ~11KB | 中等 | 优秀 | 大型应用、复杂流程 |
| Jotai | 3.1KB | 低 | 有 | 原子状态 |
| TanStack Query | 13KB | 中等 | 优秀 | 服务端状态 |

React Context — 何时使用
Context是内置的,非常适合不频繁变化的全局数据。
// ✅ Context的良好使用:主题
const ThemeContext = createContext<'light' | 'dark'>('light');
function ThemeProvider({ children }) {
const [theme, setTheme] = useState<'light' | 'dark'>('light');
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
{children}
</ThemeContext.Provider>
);
}
// ✅ Context的良好使用:当前用户(很少变化)
const AuthContext = createContext<{ user: User | null; logout: () => void } | null>(null);
function useAuth() {
const ctx = useContext(AuthContext);
if (!ctx) throw new Error('useAuth must be used within AuthProvider');
return ctx;
}
Context性能问题
// ❌ 问题:任何Context值的变化都会重新渲染所有消费者
const AppContext = createContext({
user: null,
cart: [], // 频繁变化
theme: 'light', // 很少变化
notifications: [], // 频繁变化
});
// 当购物车更新时,<ThemeToggle />即使不使用cart也会重新渲染!
function ThemeToggle() {
const { theme, setTheme } = useContext(AppContext); // 订阅所有变化
return <button onClick={() => setTheme('dark')}>{theme}</button>;
}
// ✅ 解决方案:按更新频率拆分Context
const ThemeContext = createContext(null); // 很少变化
const UserContext = createContext(null); // 很少变化
const CartContext = createContext(null); // 经常变化
const NotificationContext = createContext(null); // 经常变化
Context适用于:主题、认证用户、本地化、功能开关——这些全局且不常变化的数据。

Zustand — 最佳平衡点
Zustand简单、小巧,并解决了Context的重新渲染问题。
npm install zustand
// stores/cartStore.ts
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
interface CartItem {
id: string;
name: string;
price: number;
quantity: number;
}
interface CartStore {
items: CartItem[];
addItem: (item: Omit<CartItem, 'quantity'>) => void;
removeItem: (id: string) => void;
updateQuantity: (id: string, quantity: number) => void;
clearCart: () => void;
total: () => number;
}
export const useCartStore = create<CartStore>()(
persist(
(set, get) => ({
items: [],
addItem: (newItem) => set((state) => {
const existing = state.items.find(i => i.id === newItem.id);
if (existing) {
return {
items: state.items.map(i =>
i.id === newItem.id ? { ...i, quantity: i.quantity + 1 } : i
)
};
}
return { items: [...state.items, { ...newItem, quantity: 1 }] };
}),
removeItem: (id) => set(state => ({
items: state.items.filter(i => i.id !== id)
})),
updateQuantity: (id, quantity) => set(state => ({
items: quantity === 0
? state.items.filter(i => i.id !== id)
: state.items.map(i => i.id === id ? { ...i, quantity } : i)
})),
clearCart: () => set({ items: [] }),
total: () => get().items.reduce((sum, item) => sum + item.price * item.quantity, 0),
}),
{ name: 'cart-storage' } // 持久化到localStorage
)
);
// 使用Zustand — 选择器防止不必要的重新渲染
function CartIcon() {
// 仅在items.length变化时重新渲染
const itemCount = useCartStore(state => state.items.length);
return <span>{itemCount} items</span>;
}
function CartTotal() {
// 仅在total变化时重新渲染
const total = useCartStore(state => state.total());
return <span>${total.toFixed(2)}</span>;
}
function AddToCartButton({ product }) {
const addItem = useCartStore(state => state.addItem);
return <button onClick={() => addItem(product)}>Add to Cart</button>;
}
Zustand与TypeScript和DevTools
import { create } from 'zustand';
import { devtools, persist } from 'zustand/middleware';
const useStore = create<Store>()(
devtools( // Chrome DevTools支持
persist( // localStorage持久化
(set) => ({
// ... store定义
}),
{ name: 'my-store' }
),
{ name: 'MyStore' } // DevTools显示名称
)
);

Redux Toolkit — 适用于复杂应用
Redux Toolkit (RTK) 现代化了Redux,样板代码大大减少。
npm install @reduxjs/toolkit react-redux
// store/slices/userSlice.ts
import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit';
interface User {
id: string;
name: string;
email: string;
role: 'admin' | 'user';
}
interface UserState {
currentUser: User | null;
users: User[];
loading: boolean;
error: string | null;
}
// 异步thunk,自动生成pending/fulfilled/rejected动作
export const fetchUsers = createAsyncThunk(
'users/fetchAll',
async (_, { rejectWithValue }) => {
try {
const response = await fetch('/api/users');
if (!response.ok) throw new Error('Failed to fetch');
return await response.json();
} catch (error) {
return rejectWithValue(error.message);
}
}
);
const userSlice = createSlice({
name: 'users',
initialState: {
currentUser: null,
users: [],
loading: false,
error: null,
} as UserState,
reducers: {
setCurrentUser: (state, action: PayloadAction<User>) => {
state.currentUser = action.payload; // Immer允许“可变”写法
},
logout: (state) => {
state.currentUser = null;
},
updateUser: (state, action: PayloadAction<Partial<User> & { id: string }>) => {
const index = state.users.findIndex(u => u.id === action.payload.id);
if (index !== -1) {
state.users[index] = { ...state.users[index], ...action.payload };
}
},
},
extraReducers: (builder) => {
builder
.addCase(fetchUsers.pending, (state) => {
state.loading = true;
state.error = null;
})
.addCase(fetchUsers.fulfilled, (state, action) => {
state.loading = false;
state.users = action.payload;
})
.addCase(fetchUsers.rejected, (state, action) => {
state.loading = false;
state.error = action.payload as string;
});
},
});
export const { setCurrentUser, logout, updateUser } = userSlice.actions;
export default userSlice.reducer;
// store/index.ts
import { configureStore } from '@reduxjs/toolkit';
import userReducer from './slices/userSlice';
import cartReducer from './slices/cartSlice';
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
export const store = configureStore({
reducer: {
users: userReducer,
cart: cartReducer,
},
// RTK自动包含redux-thunk和Immer
});
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
// 类型化的hooks(使用这些代替原始hooks)
export const useAppDispatch = () => useDispatch<AppDispatch>();
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
RTK Query — 内置数据获取
// store/api/usersApi.ts
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
export const usersApi = createApi({
reducerPath: 'usersApi',
baseQuery: fetchBaseQuery({
baseUrl: '/api',
prepareHeaders: (headers, { getState }) => {
const token = (getState() as RootState).auth.token;
if (token) headers.set('authorization', `Bearer ${token}`);
return headers;
},
}),
tagTypes: ['User'],
endpoints: (builder) => ({
getUsers: builder.query<User[], void>({
query: () => '/users',
providesTags: ['User'],
}),
getUserById: builder.query<User, string>({
query: (id) => `/users/${id}`,
providesTags: (result, error, id) => [{ type: 'User', id }],
}),
updateUser: builder.mutation<User, Partial<User> & { id: string }>({
query: ({ id, ...patch }) => ({ url: `/users/${id}`, method: 'PATCH', body: patch }),
invalidatesTags: (result, error, { id }) => [{ type: 'User', id }],
}),
}),
});
export const { useGetUsersQuery, useGetUserByIdQuery, useUpdateUserMutation } = usersApi;
// 使用
function UserList() {
const { data: users, isLoading, error } = useGetUsersQuery();
// 自动缓存、后台重新获取、加载状态!
}
决策指南
是本地组件状态吗?
→ useState / useReducer
是服务端/异步数据(API响应)吗?
→ TanStack Query 或 RTK Query(不是Zustand/Redux)
是共享的全局状态吗?
→ 小型/中型应用:Zustand
→ 大型应用且流程复杂:Redux Toolkit
是很少变化的UI状态吗?(主题、认证、本地化)
→ React Context
总结
2026年:
- Context:主题、认证、本地化。简单、内置、免费。避免用于频繁更新的状态。
- Zustand:大多数应用的最佳平衡点。小巧、简单、快速、开发体验好。
- Redux Toolkit:大型应用、复杂异步流程、需要时间旅行调试。
- TanStack Query/RTK Query:服务端状态。使用它们代替将API响应放入Redux。
→ 使用 JSON Viewer 检查和格式化你的状态快照。