用途
XState v5 技能用于状态机与状态图工程,优先关注状态建模的合理性,其次才是 API 正确性。该技能仅面向 v5,遇到 v4 风格的示例、博客、回答或本地代码时,应进行翻译转换,而不是混用版本。官方建议优先参考本地仓库代码与官方 v5 文档,而非泛化的记忆。
主要能力
该技能可帮助完成以下任务:在 xstate 与 @xstate/store 之间做出选择;从混乱需求中设计出合理的机器或 actor 系统;以一致的现代 XState v5 TypeScript 风格编写代码;审查、修复或改进既有 XState 代码;迁移出现的遗留 v4 风格模式;当问题不只是 assign(...) 加 fromPromise(...) 时,选择合适的 actor 类型与 action 形态;在需要时把机器与 actor 接入 @xstate/react、@xstate/vue、@xstate/svelte 或 @xstate/solid。
工具选择
当领域是简单的事件式状态管理时,优先使用 @xstate/store:没有需要协调、编排或显式生命周期建模的有限模式,没有调用的异步过程,没有 actor 通信,也不需要 guard 转换、延迟转换、并行状态或历史等状态机概念。简单获取或变更逻辑若不需要机器级编排,也可归入 @xstate/store。在 Seed 中推荐或导入前,需先确认 @xstate/store 已安装;若未安装,只有在更简单的 store 模型足以证明新增依赖合理时才建议引入。
当领域具备以下一项或多项特征时,优先使用 XState:对行为或 UI 有意义的有限模式;异步工作流、重试、取消或后台过程;多个交互过程或子 actor;显式的 guard、延迟、标签或转换规则;需要建模业务流程流而非仅更新状态。若问题简单到不需要机器,应直接说明并推荐 @xstate/store。
工作方式
需求模糊时,先勾勒机器形态:命名重要状态、事件、context、actor 与标签,简要指出不确定性或权衡,然后写代码。需求已清晰时,可缩短或隐含勾勒,直接进入代码。不要为了概念纯粹性过度重构既有代码。
建模前可使用以下问题:有限状态有哪些?把模式放进状态而不是 context。context 应只保留持久数据,不存放可推导的布尔值或重复模式。领域事件是什么?优先采用有意义的名称,常以点分隔。什么应是 guard 而非单独分支状态?哪些副作用应作为调用的 actor 而非转换 action?事件能否携带所需数据,而不是在 context 中暂存中继数据?fromPromise(...) 是否真的是合适的 actor,还是应使用回调/订阅协议随时间回传事件?机器是否应向周边系统发出事件,而非让消费者从 context 推断一切?子关注点是否应作为派生/调用的 actor,而非增加父级复杂度?父级是否真的需要这些额外中间状态,还是应由子 actor 拥有内部细节?哪些状态需要标签来表达 UI 语义?UI 能否使用 snapshot.matches(...)、tags 或 snapshot.can(...) 替代额外布尔值?
首选 v5 模式
新代码除非本地代码库有强烈理由,否则优先采用:仅 TypeScript;优先 setup({...}).createMachine({...});在 setup(...) 中定义具名 action、guard、actor 与延迟;在提升一致性时优先使用 { target: 'next' } 这类转换对象而非简写;为保持形态一致,即使单个 action 也优先使用数组;当意图可复用或具名时,优先使用 { type: 'track' } 或 { type: 'isValid', params: ... } 这类 action 与 guard 对象;优先使用 tags: [] 表达 UI 语义与横切状态含义;优先使用面向领域的事件名;优先使用普通函数计算派生值;优先使用事件负载而非临时 context 中继;优先通过 params 把数据传入具名 action 与 guard。
不要把 assign(...) 当作唯一的 action 模式。对于超出简单 context 更新的类型化可复用逻辑,可考虑来自 setup(...) 对象的 setup 作用域辅助函数,如 machineSetup.createAction(...)、machineSetup.enqueueActions(...)、machineSetup.emit(...)。当具名 assign(...) action 更新多个 context 属性时,每个属性更新器共享同一 params 类型,应为所有更新字段使用一个一致 params 对象,或拆分为独立的具名 action。当实现必须检查 event 且类型不明显时,优先使用 assertEvent(...) 进行收窄。避免 as any 及其他宽松类型断言。有意选择 actor 逻辑:单请求单结果优先 fromPromise(...),订阅、定时器、外部回调及随时间回传事件的多事件协议优先 fromCallback(...)。当机器应直接通知周边系统时,可考虑 emit(...)。尽量保持父状态粗粒度。若展示多个文件,请完整接线,包含真实 import/export。
UI 集成
优先让机器驱动 UI 行为:用 snapshot.matches(...) 检查有限模式,用 tags 做加载、保存或脏状态等语义检查,用 snapshot.can(...) 判断某事件当前是否有效,避免用成堆手动布尔值重述机器真相。若组件拥有小型本地 actor,useMachine(...) 通常足够。若 actor 共享、长生命周期或对性能敏感:创建或获取一次 actor ref,用 useSelector(...) 读取切片,actor 跨子树共享时使用 actor context/provider 辅助。
审查、迁移与持久化
审查或修复 XState 代码时,关注:有限模式存于 context 而非状态;应拆分为子 actor 的巨型机器;隐藏在随机回调或混入 assigner 的副作用;同一机器中混用 v4 与 v5 概念;描述 UI 机制而非领域含义的状态名与事件名;应被 matches(...)、tags 或 selector 替代的额外布尔值;问题简单时错失使用 @xstate/store 的机会;具名 assign(...) action 的属性更新器隐式期望不同 params 形态。避免过度分解。
迁移时,除非用户要求大范围迁移,否则逐步、局部地向 v5 翻译。常见目标:cond -> guard;schema -> types;services -> actors;interpret(...) -> createActor(...);旧函数签名 -> 解构的 v5 参数。迁移应保留本地结构,仅改动正确性、兼容性或清晰度所需部分,不擅自归一为完整首选风格,并解释任何非局部重构。
持久化或 hydration 重要时:持久化快照而不仅是 context,除非仅恢复 context 确实足够;优先 actor.getPersistedSnapshot() 保存机器状态;优先用 createActor(machine, { snapshot }) 或适配器/provider 快照选项进行恢复;不要通过猜测状态值与部分 context 自行手写恢复。
测试与可选工具
除非用户询问测试或要求测试,否则不主动引入测试指导。若用户要求,保持简短:测试关键转换与 guard、测试 actor 的正常与失败路径、针对机器状态测试 UI 而非复制有状态逻辑,并可在有用时提及基于模型的测试工具。
Stately Studio 与检查工具可辅助设计、调试与沟通,但均为可选。当用户设计机器、需要可视化或更好的调试可见性时可提及:Stately Studio 用于可视化建模与协作,Inspection API 用于观察 actor 系统,Stately Inspector 用于在运行应用中可视化检查。
限制与说明
该技能仅面向 XState v5。文中提到 Seed 主仓库当前使用 xstate@5.19.2 与 @xstate/react@4.1.3,主要位于 frontend/packages/shared/src/models/**。其他平台支持、收费、价格、具体效果或使用步骤暂未提供。