Redux 是老牌方案,Zustand 是现在更火的轻量方案,但 AI 项目前端经常还需要第三种思路。
最近连续做了几个 AI 相关前端:聊天界面、Agent 工作台、工具调用面板、知识库检索页、模型配置页。做到后面我越来越强烈地意识到一件事:
AI 项目前端最难的,往往不是调用模型 API,而是管理那些“不断变化、彼此关联、还带副作用”的状态。
比如你以为自己只是在做一个聊天页,结果实际要管理的是:
- 消息列表
- 流式输出中的中间态
- 当前是否在调用工具
- 工具调用参数和结果
- 会话上下文
- 用户操作历史
- 多个面板之间的状态同步
- 错误重试和 loading
这时候如果你还在 Redux 和 Zustand 之间来回摇摆,通常会遇到两种不同但都很真实的问题:
-
用 Redux:
-
状态定义越来越大
-
action / reducer / selector 一层层铺开
-
AI 容易补出一堆“能跑但样板很多”的代码
-
用 Zustand:
-
起步很轻,写 demo 特别快
-
但一旦业务变重,容易把 action、异步、副作用、派生逻辑全塞回 store 或 hooks
-
AI 也容易顺着这个趋势继续“越写越散”
我后来干脆把这些项目都切到了 easy-model 这种 class-based 的思路,体验差别挺明显。
AI 项目前端,为什么特别容易把状态管理写崩
传统中后台页面很多时候是“表单 + 列表 + 弹窗”。
AI 项目前端不一样,它的状态天然更像一个“运行中的系统”:
- 用户发出输入
- 模型开始流式返回
- 中途触发 tool call
- tool call 完成后继续生成
- 页面多个区域要同时更新
- 还要能插入日志、埋点、调试、回放
这类状态有两个特点:
- 业务过程很重
- 组件之间共享状态的需求很多
如果状态只是几个布尔值,Redux、Zustand、easy-model 其实都能做。
但一旦你要表达“一个 AI 会话正在发生什么”,你会发现最自然的抽象其实不是一堆独立的 hook,而是一个有字段、有方法、有行为边界的对象。
也就是这种形式:
class AIChatModel {
messages: Message[] = [];
streamingText = '';
isStreaming = false;
toolCalls: ToolCall[] = [];
activeTool: ToolCall | null = null;
@loader.load()
async sendMessage(content: string) {
this.messages.push({ role: 'user', content });
this.isStreaming = true;
const stream = await llm.stream(this.messages);
for await (const chunk of stream) {
this.streamingText += chunk;
}
this.messages.push({
role: 'assistant',
content: this.streamingText,
});
this.streamingText = '';
this.isStreaming = false;
}
}
我不是说这段代码比 Zustand “高级”。
恰恰相反,它最大的优点是:足够直觉。
字段就是状态,方法就是业务动作。你不需要在脑子里来回切 Redux 那套 action / reducer / selector,也不需要在 Zustand 里反复决定“这段逻辑到底塞 store、hook 还是 component”。
这也是 easy-model 对 AI 编程工具友好的地方
这两个月我最大的体感是,AI 对不同状态方案的“续写稳定性”差别还挺大的:
AI coding assistant 不是不能写前端,而是它特别怕“概念层级太碎”。
比如:
-
Redux 对 AI 来说不是不能写,而是容易写得太模板化
-
Zustand 对 AI 来说不是不能写,而是容易随着业务增长变得过于随手
-
easy-model 这种组织方式,对 AI 来说就比较顺:
-
一个类就能描述一个完整业务域
-
类名天然就是语义边界
-
方法名天然就是业务意图
-
字段和 UI 展示有直接映射关系
-
同一个模型可以被多个组件共享
你给 Cursor、Copilot、Claude Code、Codeium 这类工具一个 prompt:
“帮我做一个 AI 聊天页,支持会话、流式消息、工具调用状态、错误重试和全局 loading”
如果底层状态层是碎片化的,AI 往往会越写越散。
但如果你先给它一个 ChatModel、ToolPanelModel、SessionModel 这种结构,生成质量会明显更稳定。
不是 AI 变聪明了,而是你的代码组织方式让它更容易理解了。
easy-model 适合 AI 前端的点,不只是“代码少”
很多人一看 class-based 状态管理,第一反应是:这是不是只是 Redux / Zustand 之外的又一种写法?
easy-model 真正让我觉得顺手的,不只是 class,而是它把几个 AI 场景里高频的诉求放在了一起:
1. 同参数共享实例
这点很适合 AI 会话、标签页、工作区这类场景。
const chat = useModel(ChatModel, ['session-1']);
你在消息区、状态栏、工具面板里都传同样的参数,就能拿到同一份实例。
这比自己手搓一层 context + cache 要省事很多。
2. 深度 watch
AI 界面里经常要做日志、埋点、调试面板、状态变化追踪。
watch / useWatcher 这类能力很适合接这些副作用逻辑,不用把追踪逻辑塞进组件里到处飞。
3. 统一 loading
AI 项目里异步方法特别多:
- 发消息
- 拉历史记录
- 调工具
- 跑检索
- 保存配置
如果每个地方都自己维护 loading = true/false,最后经常会乱。
loader 这种统一管理方式,在复杂交互里会省很多心智负担。
4. IoC / inject
这个点不一定所有人都马上用上,但如果你在做:
- 多模型供应商适配
- 多环境接口切换
- 插件式工具注入
- Agent 工具注册
依赖注入会比把依赖到处硬编码舒服很多。
为什么我觉得这类库更适合“AI 参与开发”的时代
过去我们选状态库,更多看的是:
- 社区规模
- 学习成本
- 性能
- 生态
但现在我觉得应该再加一个维度:
它适不适合被 AI 生成、理解、修改、续写。
这个维度以前不存在,现在越来越重要。
因为很多项目不是“人手写完再让 AI 看看”,而是:
- 先让 AI 起草 70%
- 人来补边界和判断
- 再让 AI 继续扩展
这时最值钱的,不只是 API 优雅,而是:
代码结构要让 AI 不容易迷路。
easy-model 给我的感觉就是,它很适合拿来当这类项目的“中间层表达方式”:
- 对人类开发者来说足够直觉
- 对 AI 来说也足够容易模式化学习
如果你现在就在做这些东西,可以试试
我会优先推荐 easy-model 给这几类项目:
- AI 聊天/Agent 前端
- 多面板协作型工作台
- 配置、检索、执行混合型页面
- 想用 AI 快速搭 UI 和业务骨架的 React 项目
- 不想再写太多样板代码,但又不想失去类型和组织性的团队
当然,它不一定适合所有项目。
如果你的页面极其简单,Zustand 依然是非常好的选择。
如果你的团队已经深度绑定 Redux 工具链,也没必要为了“换库”硬换。
但如果你已经开始出现下面这些信号:
- 一个页面里有好几个相互关联的状态域
- 组件越来越多,共享逻辑越来越乱
- AI 能生成代码,但你接手后越看越散
那 easy-model 值得你认真试一下。
最后
我现在对 easy-model 的定位很直接:
它不是为了取代 Redux 或 Zustand 而存在,而是提供一种更适合 AI 时代 React 业务建模的写法。
尤其是 AI 项目前端,这种感觉会更明显。
项目地址:
- GitHub: github.com/ZYF93/easy-…
- npm:
pnpm add @e7w/easy-model
如果你也在做 AI 前端,或者正在找一种对 AI coding assistant 更友好的 React 状态组织方式,欢迎去看看。
如果这篇对你有启发,也欢迎顺手点个 Star。