前端工程Technical Deep Dive
React 状态管理演进 —— 从 useState 到 Zustand 的完整指南
发布时间2026/03/29
分类前端工程
预计阅读3 分钟
作者吴长龙
*
状态管理的本质
01.内容
状态管理的本质
React 的核心数据流是单向的:props 向下传递,事件向上传递。但随着应用复杂度增长,状态管理成了每个开发者必须面对的问题。
阶段一:组件内部状态 useState
最简单的状态管理,每个组件维护自己的状态:
jsx snippetjsx
function Counter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}优点:简单、直观、无额外依赖 缺点:无法跨组件共享,组件树深层传递麻烦
阶段二:Context API
React 16.3 引入的 Context 解决了跨组件共享问题:
jsx snippetjsx
const ThemeContext = createContext('light');
function App() {
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
function Toolbar() {
const theme = useContext(ThemeContext); // 任意层级获取
return <div className={theme}>...</div>;
}核心问题:任何 Context 变化会导致所有消费该 Context 的组件重渲染。
优化策略:
- •拆分 Context:将不同职责的状态放入不同 Context
- •使用 useMemo:缓存 Context 的 value
- •状态细化:只传递需要的子集
jsx snippetjsx
// 不好:所有消费 UserContext 的组件都会重渲染
const UserContext = createContext();
const ThemeContext = createContext();
// 好:拆分后,theme 变化不会影响 user 相关组件
const UserContext = createContext();
const ThemeContext = createContext();阶段三:Redux —— 全局状态的黄金标准
Redux 2015 年出现,定义了状态管理的最佳实践:
三大原则:
- •单一数据源:整个应用的状态存放在一个 store 中
- •状态只读:只能通过 dispatch action 来修改状态
- •纯函数修改:reducer 必须是纯函数
javascript snippetjavascript
// Action
const increment = () => ({ type: 'INCREMENT' });
// Reducer
function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1;
default:
return state;
}
}
// Store
const store = createStore(counter);
// 使用
store.dispatch(increment());
store.getState();Redux Toolkit (RTK):2019 年推出的现代化 Redux 写法:
javascript snippetjavascript
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 { increment, decrement } = counterSlice.actions;
const store = configureStore({
reducer: counterSlice.reducer,
});RTK 内置了 Immer 支持,可以直接"可变式"修改状态。
React-Redux hooks:
jsx snippetjsx
import { useSelector, useDispatch } from 'react-redux';
function Counter() {
const count = useSelector(state => state.value);
const dispatch = useDispatch();
return <button onClick={() => dispatch(increment())}>{count}</button>;
}阶段四:轻量级方案崛起
随着应用复杂度分化,出现了更轻量的方案:
#### Zustand
javascript snippetjavascript
import { create } from 'zustand';
const useStore = create((set) => ({
count: 0,
increment: () => set(state => ({ count: state.count + 1 })),
}));
// 使用 - 无需 Provider!
function Counter() {
const { count, increment } = useStore();
return <button onClick={increment}>{count}</button>;
}优点:
- •零配置,无需 Provider 包裹
- •极小的体积(~1KB)
- •灵活的选择器,避免不必要重渲染
- •支持中间件
#### Jotai
原子化状态管理,适合复杂表单和精细控制:
javascript snippetjavascript
import { atom } from 'jotai';
import { useAtom } from 'jotai';
const countAtom = atom(0);
const doubledAtom = atom((get) => get(countAtom) * 2);
function Counter() {
const [count, setCount] = useAtom(countAtom);
const [doubled] = useAtom(doubledAtom);
return (
<div>
<button onClick={() => setCount(c => c + 1)}>{count}</button>
<p>Double: {doubled}</p>
</div>
);
}适用场景:需要细粒度控制、派生状态多的场景。
#### Valtio
代理式状态管理,代码极其简洁:
javascript snippetjavascript
import { proxy } from 'valtio';
const state = proxy({ count: 0 });
function Counter() {
const snap = useSnapshot(state);
return <button onClick={() => { state.count++; }}>{snap.count}</button>;
}状态管理选型指南
| 方案 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| useState | 简单组件、局部状态 | 无依赖、直观 | 无法跨组件共享 |
| Context | 主题、语言、全局配置 | 简单、无需库 | 重渲染问题 |
| Redux | 大型复杂应用 | 生态完善、调试强大 | 样板代码多 |
| Zustand | 中小型应用 | 轻量、简单 | 功能有限 |
| Jotai | 细粒度状态控制 | 原子化、灵活 | 学习曲线 |
| Valtio | 快速原型、简单需求 | 极简 | 灵活性差 |
最佳实践
- •优先本地状态:能用 useState 解决的不要用全局状态
- •状态最近原则:状态应该放在离使用它最近的地方
- •避免状态冗余:派生数据用 useMemo,不要存重复状态
- •选择合适的复杂度:不要过度工程化
理解每种方案的适用场景,才能做出正确的技术决策。