这不是说 Zustand 不好,而是 AI 项目前端会把很多“轻量方案”的边界很快打出来。
先说结论,免得大家看半天:
如果你做的是普通后台、普通配置页、普通业务表单,Zustand 很香。
但如果你做的是:
- AI 聊天界面
- Agent 工作台
- 工具调用面板
- 检索增强前端
- 多区域联动的 Copilot UI
那你很可能会在写着写着的时候发现:
Zustand 解决了“起步成本”,但不一定解决“复杂业务如何持续长大”。
而这恰恰是 AI 项目前端最容易踩坑的地方。
为什么 Zustand 现在这么火
先承认现实,Zustand 火不是没道理。
它几乎满足了现代 React 开发者对状态库的全部直觉期待:
- API 简单
- 上手快
- 没太多样板代码
- 写起来比 Redux 轻很多
- 比较符合“先干活再说”的开发节奏
所以很多人现在默认的选择已经不是 Redux,而是:
“要不要直接上 Zustand?”
这个判断在很多项目里都对。
问题是,AI 项目前端经常不是“很多项目”里的那一种。
AI 项目前端的复杂度,和普通页面不是一个量级
很多人低估了 AI 前端的状态复杂度。
你以为你在做的是一个聊天框,实际上你在管理的是一个微型运行时:
- 消息历史
- 流式返回
- 当前阶段状态
- 工具调用链
- 失败重试
- 日志追踪
- 多面板同步
- 会话隔离
- 可能还有 memory、context、plan、step
这类状态有个特点:
不是“量多”,而是“关系复杂”。
而关系复杂时,最怕的不是代码长,而是:
- 逻辑分散
- 语义模糊
- 副作用到处飞
- 后续接手的人和 AI 都看不清边界
Zustand 最大的优点,也可能是它的隐性问题
Zustand 的优点是轻。
但“轻”这个特性,一旦进入复杂业务,也可能变成一种风险:
- 什么都能往 store 里塞
- 什么逻辑都能先写进去
- 异步请求、派生状态、副作用、组件联动,很容易混着长
于是项目一开始通常是这样:
const useChatStore = create(set => ({
messages: [],
streamingText: '',
isStreaming: false,
setStreamingText: (text) => set({ streamingText: text }),
addMessage: (message) =>
set(state => ({ messages: [...state.messages, message] })),
}));
看起来非常舒服。
然后几周后,它可能慢慢长成这样:
const useChatStore = create((set, get) => ({
messages: [],
streamingText: '',
isStreaming: false,
toolCalls: [],
logs: [],
retries: 0,
activeSessionId: '',
contextWindow: [],
memory: [],
addMessage: () => {},
appendStreaming: () => {},
startToolCall: async () => {},
completeToolCall: () => {},
retry: async () => {},
syncContext: () => {},
rebuildMemory: () => {},
fetchHistory: async () => {},
hydrateSession: async () => {},
}));
注意,这不是 Zustand 的错。
这是因为它太顺手了,所以特别容易把“先写进去再说”变成长期默认策略。
AI 一参与开发,这个问题会被放大
这一点我体感特别强。
很多人现在都在这样开发:
- 自己先起个 store
- 让 Cursor / Copilot 补 action
- 让 AI 再补异步请求
- 再让 AI 补 UI 和联动
如果底层是一个越来越胖的 Zustand store,AI 很容易做两件事:
- 继续把新逻辑往原 store 里堆
- 或者另起一套 hooks / utils 来绕开已有结构
最后结果通常不是“不能跑”,而是:
项目越来越像一个能工作的临时产物。
这也是我后来更偏向 easy-model 的原因
easy-model 不是说一定比 Zustand 更轻。
它的优势在于:
它逼着你更早把业务边界说清楚。
比如 AI 会话、搜索工作区、Agent 执行流,你会更自然地写成:
class AgentSessionModel {
messages: Message[] = [];
streamingText = '';
status: 'idle' | 'running' | 'streaming' = 'idle';
toolCalls: ToolCall[] = [];
logs: string[] = [];
@loader.load(true)
async run(input: string) {
this.status = 'running';
this.messages.push({ role: 'user', content: input });
// ...
this.status = 'streaming';
// ...
this.status = 'idle';
}
}
这里最重要的不是 class 本身,而是它天然形成了几个好处:
- 一个模型就是一个业务域
- 字段就是状态
- 方法就是行为
- 组件只负责消费
- AI 也更容易看懂“新逻辑该往哪放”
Zustand 适合什么,easy-model 又适合什么
我现在的理解大概是:
Zustand 更适合
- 小中型 React 页面
- UI 状态为主的项目
- 快速验证想法
- 团队希望极低心智负担起步
easy-model 更适合
- AI 项目前端
- 业务状态和行为耦合很强的页面
- 多组件共享同一业务实例
- 需要让 AI coding assistant 长期参与开发
- 希望项目越长越像“领域模型”,而不是“越来越胖的 store”
真正值得关注的不是“谁更火”,而是谁更扛业务
现在社区里 Zustand 确实更热。
但技术选择最怕的一件事,就是把“社区热度”错当成“业务适配度”。
尤其是 AI 项目前端,这类项目的复杂度非常容易后置爆发。
前两周你会觉得 Zustand 写得真爽。
第六周你可能会开始问:
- 为什么这个 store 已经这么大了?
- 为什么请求逻辑和 UI 联动逻辑缠在一起?
- 为什么 AI 每次改代码都在不同地方补丁?
- 为什么我越来越不敢让它继续自动改?
这个时候你才会发现,真正贵的不是起步那一天,而是后面每一次扩展。
最后
所以我的观点不是:
“别用 Zustand。”
而是:
“如果你做的是 AI 项目前端,别默认 Zustand 一定就是最优解。”
至少,把 easy-model 这种更强调业务建模和 AI 可理解性的方案也一起放进候选列表里。
因为未来前端架构要回答的问题,已经不只是:
- 人类开发者好不好写
还包括:
- AI 好不好理解
- AI 好不好续写
- 项目复杂之后会不会快速失控
项目地址:
- GitHub: github.com/ZYF93/easy-…
- npm:
pnpm add @e7w/easy-model
如果你也在做 AI 前端,或者最近正被 Zustand store 越长越胖这件事折磨,欢迎去看看。
顺手点个 Star,也算帮更多人看到另一种思路。