React 状态管理进化史:从 setState 到 useSyncExternalStore
前端状态管理方案层出不穷——Redux、MobX、Zustand、Jotai、Recoil……它们之间到底是什么关系?各自解决了什么问题?本文从 React 状态管理的演进历史出发,梳理每个方案的核心思想和适用场景,帮你建立自己的状态管理选型框架。
React 状态管理进化史:从 setState 到 useSyncExternalStore
一切的起点:setState
2013 年 React 发布时,状态管理很简单——setState。
class Counter extends React.Component {
state = { count: 0 };
render() {
return (
);
}
}这在组件内部工作得很好,但很快暴露了问题:跨组件共享状态怎么办?
答案是把状态"提升"到最近的公共祖先,然后通过 props 逐层传递。这就是 prop drilling——写起来繁琐,维护起来痛苦。
Redux 时代:单一状态树
2015 年,Redux 横空出世,带来了三个核心概念:
Store:单一数据源,整个应用的状态存在一棵对象树里
Action:描述"发生了什么"的普通对象
Reducer:纯函数,接收旧状态和 Action,返回新状态
// Action
const increment = () => ({ type: 'INCREMENT' });
// Reducer
const counter = (state = 0, action) => {
switch (action.type) {
case 'INCREMENT': return state + 1;
default: return state;
}
};
// Store
const store = createStore(counter);
store.dispatch(increment());Redux 解决了状态变化的可预测性问题——每次状态变更都有迹可循。但它也有代价:样板代码多,概念负担重。一个简单的计数器需要 action type、action creator、reducer、connect——四个文件。
原子化状态:Recoil 和 Jotai
2020 年 Facebook 推出 Recoil,提出了"原子"的概念:
const countAtom = atom({ key: 'count', default: 0 });
function Counter() {
const [count, setCount] = useRecoilState(countAtom);
return ;
}每个 atom 是独立的状态单元,组件只订阅自己需要的 atom。这解决了 Redux 的"全局重渲染"问题——Redux 中任意状态变更会通知所有 connect 的组件,而 atom 只通知订阅了该 atom 的组件。
Jotai 沿用了 atom 概念但去掉了 key 的要求,API 更简洁。
轻量化革命:Zustand
Zustand 的核心理念是"Redux 的精华,去掉样板":
const useStore = create((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
}));不需要 Provider 包裹、不需要 action type 常量、不需要 dispatch。直接调用函数即可。
回到原点:useSyncExternalStore
React 18 引入了 useSyncExternalStore——一个专门用于订阅外部 store 的 Hook。有意思的是,Zustand 和 Redux 的 React 绑定最终都基于这个 API。
这像是在说:React 终于"官方承认"了外部状态管理的必要性,并给了标准化的集成方式。状态管理的轮回完成了——从 React 内置到第三方繁荣,再回到 React 官方基础能力。
总结
没有"最好"的状态管理方案,只有最适合当前场景的:
组件内部状态 →
useState中等复杂度、需要中间件 → Zustand
大型应用、需要时间旅行调试 → Redux Toolkit
高频更新、细粒度订阅 → Jotai
选择的关键不是"哪个最流行",而是"哪个最匹配你当下的问题"。
如果本文对你有帮助,欢迎点赞收藏~ 有不同意见欢迎在评论区交流讨论。