You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现MobX派生/computed值的分层因果变更日志

MobX派生值网络同构变更日志构建问题

我搭建了一套运行流畅的MobX派生值网络,目前希望在单个事务上下文内,面向用户可视化部分变更,以及触发对应变更的上游依赖,即构建与发生变更的computed树在结构上同构的数据结构,实现分层日志展示,示例效果如下:
分层日志展示示例

在使用MobX之前,我通过自定义update函数实现计算逻辑,可以依靠调用栈、通过入栈出栈维护日志上下文的方式构建同构日志(多数场景下可以默认update执行时就有需要记录的变更,部分场景会缓存旧值做比对),示例代码如下:

updateA(){
    pushLog("A") // 创建"A"日志节点
    if (...) updateX()
    else (...) updateB();
    popLog()
}
updateB(){
    pushLog("B") // 创建"B"日志节点
    updateC()
    if (...)  updateX()
    popLog(); // 弹出B日志节点,所有节点按入栈出栈规则正确嵌套
}

updateC(){
   pushLog("C")
   // 对应计算逻辑
   popLog();
}

updateX(){
   pushLog("X")
   // 对应计算逻辑
   popLog();
}

切换MobX后遇到的卡点

使用MobX的computed和reaction能力后,没有清晰的同步调用栈,无法沿用旧方案正确构建同构日志树,具体问题如下:

  • 若为每个computed创建独立reaction:reaction会在事务末尾批量执行,既无确定执行顺序,也无法获取完整因果链路信息
  • 若在事务结束后组装日志树:记录每个computed的调试名,在reaction中做依赖查找,判断已有日志条目是否为当前computed的依赖,再将新日志条目挂载到对应父节点下——但日志本身是observable,事务结束后更新日志会触发额外的重算逻辑,不符合预期,理想状态下触发computed变更的事务本身就应包含日志的变更
  • 若直接在computed计算函数内部打日志:当computed存在多个依赖时,无法确认具体是哪个/哪些依赖触发了本次computed重算,若自行缓存旧值做比对,又和MobX已有的变更检测能力重复,代码冗余度高

实际应用场景

很多桌游的规则可以用函数式派生逻辑表达,例如《卡坦岛》中,玩家是否获胜是总点数的派生值,总点数是玩家连接道路数量(及其他因素)的派生值。
当player.won == true时触发胜利UI提示很容易实现,但理想效果是展示胜利的完整因果链路:例如胜利是因为获得了最长路,获得最长路是因为玩家放置了道路,层级展示效果如下:

放置道路

获得「最长路」!+10点

胜利!

要展示这类因果关系,不仅需要知道初始变更(放置道路),还需要知道触发player.won变更的完整派生链。当初始变更到最终结果的依赖树存在多条路径时,该能力尤为必要:例如某卡坦岛变体规则中,放置道路可能形成所有对手都被封锁的局面,直接判定默认胜利,对应链路为:

放置道路

所有对手被封锁

胜利!

内容的提问来源于stack exchange,提问作者Ian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 04:21:14