视图模型(view model) 前端与交互
界面状态的**纯数据**投影:不是 DOM,而是一份由 reducer 生成、渲染层唯一读取的数据结构(消息块数组、状态、审批提示、输入队列)。DOM 只是它的投影;它让界面状态**可测、可回放、可恢复**——断线重连后把持久化事件重放一遍,界面就回来了。
它是什么
视图模型(view model)是界面状态的纯数据投影:不是 DOM,而是一份由 reducer 生成、渲染层唯一读取的数据结构——消息块数组、状态、审批提示、输入队列。DOM 只是它的投影;渲染层把视图模型画出来,但不承担任何状态逻辑。判断标准一句话:把所有 DOM 操作删掉,界面状态还能被完整描述吗? 能,说明有视图模型;不能,状态就散落进了 DOM。
为什么中间必须有它
流式界面的事件(text_delta/tool_call_start/tool_result…)乱序到达、反复改写状态;如果每个事件回调直接改 DOM(el.textContent += delta),就没有任何一份代码能回答「现在界面上到底是什么」。视图模型把状态收拢成一份数据:消息是块的保序数组(文本块 + 工具块交错,到达顺序即渲染顺序),thinking 是派生态(streaming + 空消息块时显示),pendingApproval、inputQueue 都是显式字段。
三个免费能力
reducer 是纯函数,同样的 (state, event) 序列永远得到同样的结果,于是视图模型天然可测(判题测试注入脚本事件流、断言视图模型,无需浏览器)、可回放(线上出 bug,把事件日志重放一遍即复现)、可恢复(断线重连后把持久化事件重放回来,界面就回来了——这是第 16 章断线恢复在前端的接口)。
在本教程的位置
第 17 章的 reduceViewModel 产出视图模型、renderFrame 只读视图模型;它与UI 状态机、状态守卫构成「事件 → 状态 → 数据 → 渲染」的单向数据流。