zustand vs jotai 状态管理对比:轻量级方案的选型指南
Redux 太重,Context API 太容易嵌套地狱,这几年 zustand 和 jotai 凭借"够用且足够轻"的特点赢得了大量用户。
但很多人只知道它们都"轻",不知道哪个更适合自己的项目。两者虽然都能解决问题,设计哲学和使用场景其实差异很大。
1. 设计哲学对比
zustand 的思想
- 单一集中的 store(类似迷你 Redux)
- 订阅机制(只推送变化了的部分)
- 显式 action,易于时间旅行与调试
jotai 的思想
- 原子化状态(Atom),类似 Recoil
- 细粒度依赖,组件只订阅需要的 atom
- 组合性强,易于分割和复用
通俗理解:zustand 是"一个大盒子里放所有状态",jotai 是"很多小盒子,需要时才组合"。
2. API 与使用姿态对比
zustand 的用法
import create from 'zustand'
const useStore = create((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 }))
}))
// 组件中
const count = useStore((state) => state.count)
特点:一个 hook,就能访问和修改整个 store。
jotai 的用法
import { atom, useAtom } from 'jotai'
const countAtom = atom(0)
const doubleAtom = atom(
(get) => get(countAtom) * 2
)
// 组件中
const [count, setCount] = useAtom(countAtom)
特点:每个状态是一个 atom,hook 返回 value, setter,类似 useState。
3. 性能特征对比
zustand
- 默认订阅整个 store,但可用 selector 限制重新渲染
- selector 相等性判断用户自己控制
- 适合"状态不会特别多"的情况
jotai
- 每个 atom 独立订阅,天然粒度细
- 组件只在真正使用的 atom 变化时才重新渲染
- 适合"atom 众多但每个组件用的少"的情况
实际上,两者都提供了性能调优工具,关键看使用方式。
4. 异步与派生状态
zustand 处理异步
const useStore = create((set) => ({
user: null,
fetchUser: async (id) => {
const user = await API.getUser(id)
set({ user })
}
}))
直接在 action 中处理,类似传统 Redux middleware。
jotai 处理异步
const userAtom = atom(
async (get) => {
const userId = get(userIdAtom)
return API.getUser(userId)
}
)
用 atom 的 async getter,自动处理 Promise。
zustand 更直白,jotai 更"响应式"。
5. DevTools 与调试能力
zustand
- 官方有 Redux DevTools 插件支持
- 时间旅行调试
- 状态变化清晰可追踪
jotai
- 官方有 devtools 组件,but 不如 zustand 成熟
- 原子化了,所以单次变化的影响范围更明确
大型应用如果对调试有执念,zustand 更成熟。
6. 对比速查表
| 维度 | zustand | jotai |
|---|---|---|
| 学习曲线 | 低(类似 useState) | 中低(需理解 atom) |
| 状态拆分 | 灵活(自己设计) | 强制原子化 |
| 细粒度订阅 | 需要手写 selector | 天然细粒度 |
| 异步处理 | action 中写 | atom 的 async getter |
| DevTools | 成熟 | 初步支持 |
| 性能(小应用) | 好 | 差别不大 |
| 性能(大应用) | 需要优化 | 更有优势 |
| 生态 | 中等 | 较小 |
7. 选型建议
选 zustand 如果:
- 项目规模小到中等(< 50 个状态值)
- 希望一上手就能快速开发
- 团队熟悉 Redux 思想
- 看重 DevTools 调试体验
选 jotai 如果:
- 应用状态众多且复杂
- 需要很强的组合性和灵活性
- 团队认可原子化思想
- 性能是核心考量(成百上千的 atom)
8. 常见失败案例
zustand 误区
- 把整个应用的状态放一个 store,结构臃肿
- 忘记用 selector 优化性能
jotai 误区
- atom 拆分过细,导致组件中 useAtom 调用过多
- 没有建立好的 atom 命名与组织规范


