文章目录
在 HOW - React 状态模块化管理和按需加载(一) - react-redux 中我们已经掌握了 react-redux 的动态模块加载(replaceReducer + React.lazy)这一进阶用法,说明你对状态管理的架构思维已经很成熟了。
今天,我们来介绍一下其他方案 ------ TanStack Query、Jotai、Zustand、Valtio、Nuqs、XState ------ 它们代表了 React 生态中几种不同哲学的状态管理思路。
一览表:状态管理方案的定位对比
| 库名 | 核心定位 | 主要用途 | 学习曲线 | 特点简述 |
|---|---|---|---|---|
| React-Redux | 事件驱动 + Store中心化 | 全局状态(复杂应用) | 中等偏高 | 结构清晰、生态成熟、可扩展性强 |
| TanStack Query (React Query) | 服务端状态管理 | 异步数据请求缓存 | 低 | 自动缓存、刷新、错误处理、请求去重 |
| Jotai | 原子化状态(Recoil思路) | 简单/中型应用 | 低 | 无样板代码,直接用 hooks 管理状态 |
| Zustand | 轻量化 Store,Flux 风格(Radix 思路) | 中小型应用全局状态 | 低 | 极简API,无 Provider,无样板 |
| Valtio | 响应式代理状态 | 简单全局或局部状态 | 低 | 类似 Vue 的 reactive,直接修改对象 |
| Nuqs | URL 状态同步 | 搜索、筛选、分页 | 低 | 把状态同步到 URL Query 参数 |
| XState | 状态机 / 状态图 | 流程、异步、复杂状态流 | 高 | 可视化、状态可预测,理想用于复杂业务流 |
应用场景推荐
| 应用需求 | 推荐方案 |
|---|---|
| 异步请求 + 缓存 | 🟢 TanStack Query |
| 小型项目全局状态 | 🟢 Zustand / Jotai / Valtio |
| 大型项目全局状态 | 🟢 Redux Toolkit |
| 状态同步到URL | 🟢 Nuqs |
| 复杂流程(状态流) | 🟢 XState |
每种状态库的"哲学"
TanStack Query(React Query)
关键词:Server State(服务端状态)
用途 :不是替代 Redux,而是专门管理「异步请求」和「缓存」的。
核心思想 :你不用自己写 useEffect + useState + fetch,交给 Query 自动处理数据请求、缓存、重试、失效刷新等。
示例:
ts
const { data, isLoading } = useQuery({
queryKey: ['user', id],
queryFn: () => fetch(`/api/user/${id}`).then(res => res.json())
});
优点:
- 自动缓存和刷新机制(时间、依赖、焦点重取)
- 内置错误和加载状态
- 轻松分页、无限滚动
- SSR / SWR 支持好
缺点:
- 仅适用于服务端数据(Server State)
- 不适合保存 UI 状态(如弹窗开关、表单输入)
Redux + React Query 是常见组合:Redux 管理 client state,Query 管理 server state。
更具体的内容可以阅读:WHAT - react-query(TanStack Query) vs swr
Zustand
关键词:简洁、Hooks Store、Flux 思路
用途 :全局状态管理的极简方案。
设计哲学 :不搞 Action/Reducer,只写逻辑函数和状态,像写 useState 一样。
示例:
ts
import { create } from 'zustand';
const useStore = create((set) => ({
count: 0,
increase: () => set((s) => ({ count: s.count + 1 })),
}));
function Counter() {
const { count, increase } = useStore();
return <button onClick={increase}>{count}</button>;
}
优点:
- 简洁、直接上手
- 无 Provider、无 context 性能损耗
- 支持中间件(persist、immer、devtools)
- 支持拆分模块
缺点:
- 逻辑组织随意,大型项目需自定规范
- 类型推断有时需要额外声明
推荐使用场景:
中小型项目全局状态管理、游戏UI、仪表盘、管理后台等。
Jotai
关键词:原子化、Recoil风格、函数式
用途:将每个状态单元(Atom)当成独立的 store。你可以组合 atom 来构建复杂状态。
示例:
ts
import { atom, 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 <button onClick={() => setCount(count + 1)}>
{count} → {doubled}
</button>;
}
优点:
- 类似函数式编程思想
- 原子可组合、依赖追踪自动更新
- 与 Suspense / Concurrent 特性兼容
缺点:
- 大量原子时依赖关系调试较复杂
- 不如 Zustand 直观
推荐使用场景:
中小项目、组件之间轻量共享状态、Form、UI 状态。
Valtio
关键词:Proxy 响应式、直接修改
用途:用 JS Proxy 包裹对象,自动追踪依赖,修改即触发渲染。像 Vue 的响应式系统。
示例:
ts
import { proxy, useSnapshot } from 'valtio';
const state = proxy({ count: 0 });
function Counter() {
const snap = useSnapshot(state);
return <button onClick={() => state.count++}>{snap.count}</button>;
}
优点:
- 不需要 set 函数
- 像操作普通对象一样
- 极简学习曲线
缺点:
- 调试工具较少
- 对大型项目的状态组织不够结构化
推荐使用场景:
小型项目、原型、3D 可视化、快速交互状态。
Nuqs
关键词:URL 同步状态(Next.js生态)
用途:让 URL 的 Query 参数直接反映页面状态。
比如分页、筛选、搜索参数同步到地址栏。
示例:
ts
import { useQueryState } from 'nuqs';
const [page, setPage] = useQueryState('page', parseAsInteger.withDefault(1));
优点:
- URL 与状态自动同步
- 页面刷新、分享、返回时状态保持一致
缺点:
- 不管理业务逻辑
- 仅适用于基于路由的状态同步
推荐使用场景:
数据表格分页、搜索筛选、带参数的共享链接。
XState
关键词:状态机、可视化、可预测状态流
用途:当状态变化复杂、涉及流程或异步阶段(如表单多步验证、上传流程、登录认证)时。
示例:
ts
import { useMachine } from '@xstate/react';
import { createMachine } from 'xstate';
const toggleMachine = createMachine({
id: 'toggle',
initial: 'inactive',
states: {
inactive: { on: { TOGGLE: 'active' }},
active: { on: { TOGGLE: 'inactive' }}
}
});
function Toggle() {
const [state, send] = useMachine(toggleMachine);
return <button onClick={() => send('TOGGLE')}>
{state.matches('active') ? 'On' : 'Off'}
</button>;
}
优点:
- 可预测、可调试、可可视化
- 强状态控制、事件驱动
- 理想于复杂状态流
缺点:
- 学习曲线高
- 初期开发较繁琐
推荐使用场景:
工作流系统、上传/下载管理、复杂表单、状态切换逻辑。