UI = f(statesⁿ)
现代 UI 工作常被概括为“UI = f(state)”,但开发者认为,真实应用——从 Web 前端到游戏——暴露出的状态比大多数模型承认的要更纠缠、更隐蔽。评论者分享了对状态机、事件流和确定性游戏逻辑的经验,争论“让非法状态不可表示”应严格到什么程度,并指出 React、LiveView 风格服务器或 XState 等工具如何帮助驯服复杂性,同时仍在同步、动画和多客户端行为方面留下空缺。许多人认为,游戏开发和形式化状态建模是更深入理解这些问题的宝贵实践。
游戏开发与状态建模
- 几位评论者主张先做一些简单游戏(例如纸牌接龙、基础动作游戏),以便内化这样一个事实:每一种可见的可能性都必须在某处的状态中存在。
- 即使是“简单”游戏,也很快会暴露出比最初图示多得多的状态,尤其是在网络、反作弊和回放/确定性方面。
- 复杂的棋盘/卡牌游戏(例如 Wingspan、《万智牌》)被认为令人望而生畏;人们提到状态机、事件驱动编程、栈和规则文档,作为理解和建模这类系统的工具。
- 对于确定性网络在多大程度上可实现存在争论,考虑到浮点行为、类似混沌的发散以及平台差异;锁步(lockstep)方案被认为很难但可行。
UI = f(state):优点与局限
- 许多人原则上同意,视图是状态的纯函数;游戏、回放系统以及开发/调试视图被视为强有力的证据。
- 也有人强调,“状态”必须包含中间/UI 专用状态:表单的部分输入、校验错误、加载标志、动画进度等。
- 过度热衷于“非法状态不可表示”会损害 UX(例如在用户输入时就对无效邮箱大喊大叫);有人认为有用的状态不应被建模为非法。
- 有人建议更清晰地区分:
- 领域状态(已验证的数据),
- UI 组件状态(用户此刻正在做什么),
- 以及二者之间的映射。
事件、动作与状态机
- 有人提议用事件流来思考:
state = reduce(state, event),view = fn(state),并让处理器分发事件,而不是直接变异。 - 也有人将其表述为
view, effects = fn(state, events)或以 action 为中心的模型;批评者指出,这通常最终还是会回到状态机的表述。 - 状态机以及相关工具/库反复被推荐,作为驯服复杂性的方法。
前端复杂度与架构
- 浏览器应用被描述为多个本地事件循环加上远程/分布式系统,而与后端生态相比,工具链往往较弱、粘合性很强。
- 像 React 这样的框架被认为擅长“state → DOM”,但并不负责完整的数据同步问题(实时、离线、协作);其他工具(查询、同步层)填补空白,但常常不够连贯。
- 有人主张采用以服务器为中心的 / LiveView 风格方法,把大部分状态和渲染留在服务器端,以简化推理。
- 加载/获取被强调为多状态问题(初次加载 vs 刷新 vs 追加),而那些区分“loading”和“fetching”的库受到称赞。
动画、过渡与隐式状态
- 当数据在动画完成前就变化时,过渡/动画会挑战天真的“UI = f(state)”观点。
- 建议的修复方式包括:把动画状态/进度显式建模为状态,或者依赖平台级声明式动画,同时把开始/结束状态保留在应用状态中。
- 总体上,大家更倾向于:一切都是状态,但其中一部分是隐式的,或者由平台处理。