创作者:Yardon |GitHub:github.com/YardonYan |版本:v1.0
什么时候需要状态管理
先泼一盆冷水:大多数 React 应用不需要 Redux。
这句话不是我说的,是 Redux 的作者 Dan Abramov 本人说的。他在 2020 年就公开表示,在他参与的大多数项目中,Redux 已经不再是最好的选择。
那么什么时候真的需要「状态管理库」?
当你的应用满足以下任意一个条件时:
- 超过 3 层嵌套的组件需要共享同一个状态
- 多个不相关的页面需要访问同一份数据
- 状态变更的逻辑非常复杂(多个 action 之间有依赖关系)
- 需要时间旅行调试(undo/redo)
其他情况?useState+useContext足够了。
React 自带的方案回顾
在介绍第三方库之前,先把 React 自带的工具说清楚。
Props Drilling(属性穿透)
最基础的方式就是通过 props 一层层往下传:
App → Header → NavBar → Logo ↓ UserMenu → Avatar → Dropdown → Item如果 UserMenu 和 NavBar 都需要访问currentUser,而currentUser定义在 App 组件里——你得把它一层层往下传。这在浅层嵌套时没问题,但如果你的组件树有 5-6 层深,每层都要"过手"一个跟它们毫无关系的 props,这就成了「属性穿透地狱」。
想象你在一栋公寓里,每层都住着互不相识的邻居,但暖气管道要穿过每一家的客厅。物业公司的员工(中间组件)被迫了解每家每户的暖气情况——尽管他只需要把暖气送到就行了。
Context API:内置的跨组件通信
Context就是来解决这个问题的——让你在组件树的任意位置访问数据,而不需要手动层层传递。
Context API:轻量级全局状态
基本用法
// ThemeContext.jsx import { createContext, useContext, useState } from 'react'; const ThemeContext = createContext(); export function ThemeProvider({ children }) { const [theme, setTheme] = useState('dark'); function toggleTheme() { setTheme(t => t === 'dark' ? 'light' : 'dark'); } return ( <ThemeContext.Provider value={{ theme, toggleTheme }}> {children} </ThemeContext.Provider> ); } export function useTheme() { const context = useContext(ThemeContext); if (!context) throw new Error('useTheme 必须在 ThemeProvider 内使用'); return context; }// App.jsx import { ThemeProvider } from './ThemeContext'; function App() { return ( <ThemeProvider> <Dashboard /> </ThemeProvider> ); } // 任意子组件中 function SettingsPage() { const { theme, toggleTheme } = useTheme(); return <button onClick={toggleTheme}>当前: {theme}</button>; }Context 的性能陷阱
Context 最大的坑在于:Provider 下的所有组件都会在 Context 值变化时重新渲染。
// ❌ 每秒更新一次,所有消费者都 re-render function App() { const [time, setTime] = useState(Date.now()); useEffect(() => { const id = setInterval(() => setTime(Date.now()), 1000); return () => clearInterval(id); }, []); return <ThemeContext.Provider value={{ time }}>...</ThemeContext.Provider>; } // ✅ 只暴露必要的状态 function App() { const [time, setTime] = useState(Date.now()); const { theme } = useThemeContext(); // 只订阅需要的 useEffect(() => { const id = setInterval(() => setTime(Date.now()), 1000); return () => clearInterval(id); }, []); return <ThemeContext.Provider value={{ theme, time }}>...</ThemeContext.Provider>; }最佳实践:按功能拆分成多个独立的 Context。
// 主题一个 Context,用户信息一个 Context,购物车一个 Context // 每个 Context 只订阅它真正需要的数据 <ThemeContext.Provider value={theme}> <UserContext.Provider value={user}> <CartContext.Provider value={cart}> <App /> </CartContext.Provider> </UserContext.Provider> </ThemeContext.Provider>这样只有购物车变了,Header 里的主题切换按钮才不会无辜地重新渲染。
Zustand:极简主义的代表
Zustand 是 2020 年后最火的状态管理库。它用起来非常简单——5 分钟就能上手。
核心概念
// store/useCartStore.js import { create } from 'zustand'; const useCartStore = create((set, get) => ({ items: [], total: 0, addItem: (product) => set((state) => ({ items: [...state.items, product], total: state.total + product.price, })), removeItem: (id) => set((state) => { const item = state.items.find(i => i.id === id); return { items: state.items.filter(i => i.id !== id), total: state.total - (item?.price || 0), }; }), clearCart: () => set({ items: [], total: 0 }), // 直接读取 state,不需要 hooks getItemCount: () => get().items.length, }));// 在组件中使用 function CartIcon() { const itemCount = useCartStore(s => s.items.length); return <span>🛒 {itemCount}</span>; } function CartPage() { const { items, total, removeItem, clearCart } = useCartStore(); return ( <div> {items.map(item => <CartItem key={item.id} item={item} onRemove={removeItem} />)} <p>总计: ¥{total}</p> <button onClick={clearCart}>清空购物车</button> </div> ); }为什么选择 Zustand
| 特性 | Zustand | Redux Toolkit |
|---|---|---|
| 代码量 | 极简(~50行一个store) | 需要 action/reducer/store boilerplate |
| 学习曲线 | 几乎为零 | 中等(概念多) |
| DevTools | 支持 | 强大(时间旅行等) |
| 适用场景 | 中小型应用 | 大型复杂应用 |
| 包大小 | ~1KB | ~15KB |
Redux Toolkit:复杂应用的选择
Redux 曾经是 React 状态管理的代名词。2019 年 Redux Toolkit 的出现大幅降低了使用门槛,但它的复杂性依然高于 Zustand。
核心概念:Slice
// features/cart/cartSlice.jsimport{createSlice}from'@reduxjs/toolkit';constcartSlice=createSlice({name:'cart',initialState:{items:[],total:0},reducers:{addItem:(state,action)=>{state.items.push(action.payload);state.total+=action.payload.price;},removeItem:(state,action)=>{constidx=state.items.findIndex(i=>i.id===action.payload);if(idx!==-1){state.total-=state.items[idx].price;state.items.splice(idx,1);}},clearCart:(state)=>{state.items=[];state.total=0;},},});exportconst{addItem,removeItem,clearCart}=cartSlice.actions;exportdefaultcartSlice.reducer;// store/index.jsimport{configureStore}from'@reduxjs/toolkit';importcartReducer from'./features/cart/cartSlice';exportconststore=configureStore({reducer:{cart:cartReducer,user:userReducer,// ...},});// 组件中使用 import { useSelector, useDispatch } from 'react-redux'; import { addItem } from './features/cart/cartSlice'; function ProductPage({ product }) { const dispatch = useDispatch(); const isInCart = useSelector(s => s.cart.items.some(i => i.id === product.id) ); return ( <div> <h1>{product.name}</h1> <button disabled={isInCart} onClick={() => dispatch(addItem(product))} > {isInCart ? '已在购物车' : '加入购物车'} </button> </div> ); }Redux Toolkit 适合什么时候?当你有多个开发者协作的大型项目,需要严格的状态流转规范、时间旅行调试、批量操作日志时,Redux 的约束反而是优点——它强制你用规范的方式做事,不容易出现"状态不知道从哪改的"的情况。
Jotai:原子化状态管理
Jotai 是一个相对小众但很有特色的方案。它的核心概念是原子(Atom)——最小的状态单元。
// atoms.js import { atom } from 'jotai'; // 基础原子 const userAtom = atom(null); const notificationCountAtom = atom(0); // 派生原子(类似 useMemo) const hasNotificationsAtom = atom(get => get(notificationCountAtom) > 0); // 写原子 const addNotificationAtom = atom( null, (get, set) => { const current = get(notificationCountAtom); set(notificationCountAtom, current + 1); } );// 组件中只订阅需要的原子 function NotificationBadge() { const count = useAtom(notificationCountAtom)[0]; return count > 0 ? <span>{count}</span> : null; } function NotificationButton() { const [, addNotification] = useAtom(addNotificationAtom); return <button onClick={addNotification}>有新消息</button>; }Jotai 的优势是细粒度更新——只有真正用到某个原子值的组件才会重新渲染。它适合状态很多、更新很频繁的应用(比如实时协作工具、数据可视化面板)。
选型决策树
应用规模? ├── 小型(几个页面,状态简单) │ └── useState + Context API ✅ 够了 │ ├── 中型(10+ 页面,多人协作) │ ├── 状态种类多、更新频繁 │ │ └── Zustand ✅ 推荐 │ │ │ └── 需要强规范、强调试能力 │ └── Redux Toolkit ✅ │ └── 大型(复杂状态流转、undo/redo) └── Redux Toolkit ✅ 或 Recoil我的推荐(2026 年):
- 90% 的项目:
useState+Context或Zustand - 5% 的项目需要强规范:
Redux Toolkit - 5% 的项目状态极细:
Jotai
本章小结
| 工具 | 适用场景 | 代码量 | 学习成本 |
|---|---|---|---|
| useState + Context | 小型应用、简单全局状态 | 少 | 无 |
| Context API(多 Context) | 中型应用、分域全局状态 | 中 | 低 |
| Zustand | 中小型应用、需要灵活状态 | 极少 | 极低 |
| Redux Toolkit | 大型、复杂、多人协作 | 多 | 中 |
| Jotai | 细粒度状态、频繁更新 | 少 | 中 |
状态管理的本质是数据的流向和共享。选什么工具不重要,重要的是理解为什么需要它、它解决的是什么问题。下一章我们聊聊React Router——单页应用如何实现页面跳转和 URL 管理。
📌创作者:Yardon | 🏠个人网站:GlimmerAI.top
📖 本章是「React 从入门到生产」系列的第 5 章。上一章:自定义Hook | 下一章:路由与导航
🌟 如果你觉得有帮助,欢迎访问 GlimmerAI.top 查看我的更多作品。欢迎大家来观看!